Merge branch 'bug-fixes' of git://farnsworth.org/dale/linux-2.6-mv643xx_eth into...
authorJeff Garzik <jeff@garzik.org>
Wed, 24 Oct 2007 00:15:05 +0000 (20:15 -0400)
committerJeff Garzik <jeff@garzik.org>
Wed, 24 Oct 2007 00:15:05 +0000 (20:15 -0400)
777 files changed:
Documentation/Intel-IOMMU.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/9p.txt
Documentation/filesystems/Exporting
Documentation/i386/boot.txt
Documentation/kbuild/makefiles.txt
Documentation/kernel-parameters.txt
Documentation/lguest/Makefile
Documentation/lguest/lguest.c
Documentation/lguest/lguest.txt
Documentation/memory-hotplug.txt
Documentation/powerpc/mpc52xx-device-tree-bindings.txt
MAINTAINERS
Makefile
arch/alpha/kernel/pci_iommu.c
arch/arm/common/dmabounce.c
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/mach-at32ap/at32ap7000.c
arch/avr32/mach-at32ap/extint.c
arch/avr32/mach-at32ap/pm.h
arch/avr32/mach-at32ap/time-tc.c
arch/blackfin/Kconfig
arch/blackfin/Makefile
arch/blackfin/boot/Makefile
arch/blackfin/boot/install.sh [new file with mode: 0644]
arch/blackfin/configs/BF527-EZKIT_defconfig [new file with mode: 0644]
arch/blackfin/configs/BF548-EZKIT_defconfig
arch/blackfin/kernel/Makefile
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/dma-mapping.c
arch/blackfin/kernel/gptimers.c [new file with mode: 0644]
arch/blackfin/kernel/reboot.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/traps.c
arch/blackfin/lib/Makefile
arch/blackfin/lib/udivdi3.S [new file with mode: 0644]
arch/blackfin/mach-bf527/Kconfig [new file with mode: 0644]
arch/blackfin/mach-bf527/Makefile [new file with mode: 0644]
arch/blackfin/mach-bf527/boards/Makefile [new file with mode: 0644]
arch/blackfin/mach-bf527/boards/eth_mac.c [new file with mode: 0644]
arch/blackfin/mach-bf527/boards/ezkit.c [new file with mode: 0644]
arch/blackfin/mach-bf527/cpu.c [new file with mode: 0644]
arch/blackfin/mach-bf527/dma.c [new file with mode: 0644]
arch/blackfin/mach-bf527/head.S [new file with mode: 0644]
arch/blackfin/mach-bf527/ints-priority.c [new file with mode: 0644]
arch/blackfin/mach-bf533/boards/cm_bf533.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/generic_board.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/cm_bf537.c
arch/blackfin/mach-bf537/boards/generic_board.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf548/dma.c
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf561/boards/generic_board.c
arch/blackfin/mach-bf561/boards/tepla.c
arch/blackfin/mach-common/ints-priority-dc.c
arch/blackfin/mach-common/ints-priority-sc.c
arch/i386/Kconfig
arch/i386/Makefile
arch/ia64/hp/common/sba_iommu.c
arch/ia64/hp/sim/simscsi.c
arch/ia64/kernel/efi.c
arch/ia64/kernel/setup.c
arch/ia64/sn/pci/pci_dma.c
arch/m68k/kernel/dma.c
arch/m68knommu/Kconfig
arch/m68knommu/Makefile
arch/m68knommu/defconfig
arch/m68knommu/kernel/setup.c
arch/m68knommu/kernel/signal.c
arch/m68knommu/kernel/time.c
arch/m68knommu/platform/5206/config.c
arch/m68knommu/platform/5206e/config.c
arch/m68knommu/platform/520x/config.c
arch/m68knommu/platform/523x/config.c
arch/m68knommu/platform/5249/config.c
arch/m68knommu/platform/5272/config.c
arch/m68knommu/platform/527x/config.c
arch/m68knommu/platform/528x/config.c
arch/m68knommu/platform/5307/config.c
arch/m68knommu/platform/5307/entry.S
arch/m68knommu/platform/5307/pit.c
arch/m68knommu/platform/5307/timers.c
arch/m68knommu/platform/532x/config.c
arch/m68knommu/platform/5407/config.c
arch/mips/Kconfig
arch/mips/Kconfig.debug
arch/mips/Makefile
arch/mips/cobalt/Makefile
arch/mips/cobalt/setup.c
arch/mips/cobalt/time.c [new file with mode: 0644]
arch/mips/kernel/Makefile
arch/mips/kernel/cevt-gt641xx.c [new file with mode: 0644]
arch/mips/kernel/cevt-r4k.c
arch/mips/kernel/time.c
arch/mips/mips-boards/generic/time.c
arch/mips/mm/dma-default.c
arch/mips/sgi-ip27/ip27-init.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sibyte/bcm1480/irq.c
arch/mips/sibyte/bcm1480/smp.c
arch/mips/sibyte/bcm1480/time.c
arch/mips/sibyte/sb1250/irq.c
arch/mips/sibyte/sb1250/smp.c
arch/mips/sibyte/sb1250/time.c
arch/parisc/Makefile
arch/parisc/configs/712_defconfig
arch/parisc/configs/a500_defconfig
arch/parisc/configs/b180_defconfig
arch/parisc/configs/c3000_defconfig
arch/parisc/defconfig
arch/parisc/hpux/gate.S
arch/parisc/kernel/asm-offsets.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/head.S
arch/parisc/kernel/hpmc.S
arch/parisc/kernel/init_task.c
arch/parisc/kernel/pacache.S
arch/parisc/kernel/parisc_ksyms.c
arch/parisc/kernel/pci-dma.c
arch/parisc/kernel/pci.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/smp.c
arch/parisc/kernel/sys_parisc32.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/syscall_table.S
arch/parisc/kernel/time.c
arch/parisc/kernel/unwind.c
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/lib/Makefile
arch/parisc/lib/libgcc/Makefile [new file with mode: 0644]
arch/parisc/lib/libgcc/__ashldi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__ashrdi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__clzsi2.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__divdi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__divsi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__lshrdi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__moddi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__modsi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__muldi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__udivdi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__udivmoddi4.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__udivmodsi4.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__udivsi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__umoddi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__umodsi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/__umulsidi3.c [new file with mode: 0644]
arch/parisc/lib/libgcc/libgcc.h [new file with mode: 0644]
arch/parisc/lib/memcpy.c
arch/parisc/lib/milli/Makefile [new file with mode: 0644]
arch/parisc/lib/milli/divI.S [new file with mode: 0644]
arch/parisc/lib/milli/divU.S [new file with mode: 0644]
arch/parisc/lib/milli/div_const.S [new file with mode: 0644]
arch/parisc/lib/milli/dyncall.S [new file with mode: 0644]
arch/parisc/lib/milli/milli.S [new file with mode: 0644]
arch/parisc/lib/milli/milli.h [new file with mode: 0644]
arch/parisc/lib/milli/mulI.S [new file with mode: 0644]
arch/parisc/lib/milli/remI.S [new file with mode: 0644]
arch/parisc/lib/milli/remU.S [new file with mode: 0644]
arch/parisc/mm/init.c
arch/powerpc/Kconfig.debug
arch/powerpc/boot/dts/bamboo.dts
arch/powerpc/boot/dts/lite5200.dts
arch/powerpc/boot/dts/lite5200b.dts
arch/powerpc/boot/dts/sequoia.dts
arch/powerpc/boot/dts/walnut.dts
arch/powerpc/boot/treeboot-walnut.c
arch/powerpc/configs/bamboo_defconfig
arch/powerpc/configs/ebony_defconfig
arch/powerpc/configs/walnut_defconfig
arch/powerpc/kernel/dma_64.c
arch/powerpc/kernel/ibmebus.c
arch/powerpc/kernel/iommu.c
arch/powerpc/platforms/40x/Kconfig
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/52xx/lite5200.c
arch/powerpc/platforms/52xx/mpc52xx_common.c
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/ps3/system-bus.c
arch/powerpc/sysdev/bestcomm/bestcomm.c
arch/ppc/boot/Makefile
arch/s390/defconfig
arch/s390/kernel/ipl.c
arch/s390/kernel/process.c
arch/s390/kernel/smp.c
arch/s390/lib/uaccess_pt.c
arch/s390/mm/Makefile
arch/s390/mm/init.c
arch/s390/mm/pgtable.c [new file with mode: 0644]
arch/s390/mm/vmem.c
arch/sparc/kernel/ioport.c
arch/sparc/mm/io-unit.c
arch/sparc/mm/iommu.c
arch/sparc/mm/sun4c.c
arch/sparc64/Kconfig
arch/sparc64/Makefile
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/iommu.c
arch/sparc64/kernel/iommu_common.c
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/ldc.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/pci_msi.c
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/math-emu/Makefile
arch/um/drivers/ubd_kern.c
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/misc_32.c
arch/x86/boot/header.S
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/e820_32.c
arch/x86/kernel/e820_64.c
arch/x86/kernel/efi_32.c
arch/x86/kernel/head_32.S
arch/x86/kernel/io_apic_64.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-dma_64.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/pci-nommu_64.c
arch/x86/kernel/setup_32.c
arch/x86/kernel/setup_64.c
arch/x86/lguest/Kconfig [new file with mode: 0644]
arch/x86/lguest/Makefile [new file with mode: 0644]
arch/x86/lguest/boot.c [moved from drivers/lguest/lguest.c with 93% similarity]
arch/x86/lguest/i386_head.S [moved from drivers/lguest/lguest_asm.S with 73% similarity]
arch/x86/mm/pageattr_64.c
arch/x86/xen/Kconfig
arch/x86_64/Kconfig
arch/xtensa/boot/Makefile
block/ll_rw_blk.c
crypto/digest.c
crypto/hmac.c
crypto/scatterwalk.c
crypto/scatterwalk.h
crypto/tcrypt.c
crypto/xcbc.c
drivers/Kconfig
drivers/Makefile
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/base/memory.c
drivers/block/DAC960.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/cciss.c
drivers/block/cpqarray.c
drivers/block/cryptoloop.c
drivers/block/lguest_blk.c [deleted file]
drivers/block/sunvdc.c
drivers/block/sx8.c
drivers/block/ub.c
drivers/block/viodasd.c
drivers/block/virtio_blk.c [new file with mode: 0644]
drivers/bluetooth/Kconfig
drivers/bluetooth/Makefile
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btsdio.c [new file with mode: 0644]
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c [new file with mode: 0644]
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_bcsp.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_ll.c [new file with mode: 0644]
drivers/bluetooth/hci_uart.h
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/cyclades.c
drivers/char/hvc_lguest.c [deleted file]
drivers/char/virtio_console.c [new file with mode: 0644]
drivers/firewire/fw-ohci.c
drivers/ide/cris/ide-cris.c
drivers/ide/ide-probe.c
drivers/ide/ide-taskfile.c
drivers/ide/mips/au1xxx-ide.c
drivers/ieee1394/dma.c
drivers/ieee1394/sbp2.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/umem.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/hw/ehca/ehca_classes.h
drivers/infiniband/hw/ehca/ehca_hca.c
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ehca/ehca_mrmw.c
drivers/infiniband/hw/ehca/ehca_qp.c
drivers/infiniband/hw/ipath/ipath_dma.c
drivers/infiniband/hw/ipath/ipath_mr.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mthca/mthca_cq.c
drivers/infiniband/hw/mthca/mthca_doorbell.h
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/mthca/mthca_memfree.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/mthca/mthca_srq.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/iser/iser_memory.c
drivers/input/keyboard/bf54x-keys.c
drivers/input/mouse/appletouch.c
drivers/input/serio/i8042.c
drivers/input/serio/i8042.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/usbtouchscreen.c
drivers/kvm/Kconfig
drivers/kvm/kvm_main.c
drivers/kvm/lapic.c
drivers/kvm/mmu.c
drivers/kvm/vmx.c
drivers/kvm/x86_emulate.c
drivers/lguest/Kconfig
drivers/lguest/Makefile
drivers/lguest/core.c
drivers/lguest/hypercalls.c
drivers/lguest/interrupts_and_traps.c
drivers/lguest/io.c [deleted file]
drivers/lguest/lg.h
drivers/lguest/lguest_bus.c [deleted file]
drivers/lguest/lguest_device.c [new file with mode: 0644]
drivers/lguest/lguest_user.c
drivers/lguest/page_tables.c
drivers/lguest/segments.c
drivers/lguest/x86/core.c [new file with mode: 0644]
drivers/lguest/x86/switcher_32.S [moved from drivers/lguest/switcher.S with 99% similarity]
drivers/md/bitmap.c
drivers/md/dm-crypt.c
drivers/md/raid5.c
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_core.c
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/radio/miropcm20-radio.c
drivers/media/radio/radio-gemtek.c
drivers/media/video/arv.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/cpia.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88-vp3054-i2c.c
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-streams.h
drivers/media/video/ivtv/ivtv-udma.c
drivers/media/video/ivtv/ivtv-yuv.c
drivers/media/video/ivtv/ivtv-yuv.h
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/meye.c
drivers/media/video/ov511.c
drivers/media/video/planb.c
drivers/media/video/pms.c
drivers/media/video/pvrusb2/pvrusb2-encoder.c
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/se401.c
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/stradis.c
drivers/media/video/stv680.c
drivers/media/video/tuner-core.c
drivers/media/video/usbvideo/usbvideo.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/v4l2-common.c
drivers/media/video/videobuf-core.c
drivers/media/video/videobuf-dma-sg.c
drivers/media/video/videocodec.c
drivers/media/video/videodev.c
drivers/media/video/vivi.c
drivers/media/video/w9966.c
drivers/media/video/w9968cf.c
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zoran_card.c
drivers/media/video/zoran_driver.c
drivers/mmc/card/queue.c
drivers/mmc/host/at91_mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/imxmmc.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.h
drivers/mmc/host/omap.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/wbsd.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ecc.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/onenand/onenand_sim.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/cpmac.c
drivers/net/fec.c
drivers/net/lguest_net.c [deleted file]
drivers/net/mlx4/fw.c
drivers/net/mlx4/icm.c
drivers/net/niu.c
drivers/net/ppp_mppe.c
drivers/net/r8169.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/virtio_net.c [new file with mode: 0644]
drivers/parisc/ccio-dma.c
drivers/parisc/lba_pci.c
drivers/parisc/pdc_stable.c
drivers/parisc/sba_iommu.c
drivers/parisc/superio.c
drivers/pci/Makefile
drivers/pci/dmar.c [new file with mode: 0644]
drivers/pci/intel-iommu.c [new file with mode: 0644]
drivers/pci/intel-iommu.h [new file with mode: 0644]
drivers/pci/iova.c [new file with mode: 0644]
drivers/pci/iova.h [new file with mode: 0644]
drivers/pci/pci.h
drivers/pci/probe.c
drivers/pci/search.c
drivers/power/apm_power.c
drivers/s390/char/raw3270.c
drivers/s390/char/tape_class.c
drivers/s390/char/tape_class.h
drivers/s390/char/vmlogrdr.c
drivers/s390/cio/chp.c
drivers/s390/cio/css.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/sbus/char/vfc_dev.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-xxxx.c
drivers/scsi/NCR5380.c
drivers/scsi/NCR53C9x.c
drivers/scsi/NCR53c406a.c
drivers/scsi/aacraid/aachba.c
drivers/scsi/aha152x.c
drivers/scsi/aha1542.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/atari_NCR5380.c
drivers/scsi/eata_pio.c
drivers/scsi/fd_mcs.c
drivers/scsi/fdomain.c
drivers/scsi/gdth.c
drivers/scsi/ibmmca.c
drivers/scsi/ide-scsi.c
drivers/scsi/imm.c
drivers/scsi/in2000.c
drivers/scsi/ipr.c
drivers/scsi/ips.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/megaraid.c
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/oktagon_esp.c
drivers/scsi/osst.c
drivers/scsi/pcmcia/nsp_cs.h
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/scsi/ppa.c
drivers/scsi/ps3rom.c
drivers/scsi/qlogicfas408.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_lib.c
drivers/scsi/seagate.c
drivers/scsi/sg.c
drivers/scsi/st.c
drivers/scsi/sun3_NCR5380.c
drivers/scsi/sym53c416.c
drivers/scsi/tmscsim.c
drivers/scsi/ultrastor.c
drivers/scsi/wd33c93.c
drivers/scsi/wd7000.c
drivers/serial/Kconfig
drivers/serial/mcf.c [new file with mode: 0644]
drivers/usb/core/message.c
drivers/usb/image/microtek.c
drivers/usb/misc/usbtest.c
drivers/usb/storage/protocol.c
drivers/virtio/Kconfig [new file with mode: 0644]
drivers/virtio/Makefile [new file with mode: 0644]
drivers/virtio/config.c [new file with mode: 0644]
drivers/virtio/virtio.c [new file with mode: 0644]
drivers/virtio/virtio_ring.c [new file with mode: 0644]
drivers/watchdog/mpc5200_wdt.c
fs/9p/v9fs.c
fs/9p/vfs_inode.c
fs/buffer.c
fs/cifs/cifsfs.h
fs/cifs/export.c
fs/dcache.c
fs/debugfs/inode.c
fs/ecryptfs/crypto.c
fs/ecryptfs/keystore.c
fs/efs/namei.c
fs/efs/super.c
fs/exportfs/expfs.c
fs/ext2/dir.c
fs/ext2/super.c
fs/ext3/super.c
fs/ext4/super.c
fs/fat/inode.c
fs/gfs2/ops_export.c
fs/gfs2/ops_fstype.h
fs/inotify.c
fs/isofs/export.c
fs/isofs/isofs.h
fs/jffs2/acl.c
fs/jffs2/acl.h
fs/jffs2/dir.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/os-linux.h
fs/jffs2/write.c
fs/jfs/jfs_inode.h
fs/jfs/namei.c
fs/jfs/super.c
fs/libfs.c
fs/namei.c
fs/namespace.c
fs/nfs/proc.c
fs/nfs/unlink.c
fs/nfsd/export.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfsfh.c
fs/ntfs/namei.c
fs/ntfs/ntfs.h
fs/ocfs2/export.c
fs/ocfs2/export.h
fs/open.c
fs/pnode.h
fs/proc/base.c
fs/reiserfs/inode.c
fs/reiserfs/super.c
fs/xattr.c
fs/xfs/linux-2.6/xfs_export.c
fs/xfs/linux-2.6/xfs_export.h
fs/xfs/linux-2.6/xfs_super.h
include/acpi/actbl1.h
include/asm-alpha/scatterlist.h
include/asm-arm/dma-mapping.h
include/asm-arm/scatterlist.h
include/asm-avr32/arch-at32ap/board.h
include/asm-avr32/dma-mapping.h
include/asm-avr32/scatterlist.h
include/asm-blackfin/bf5xx_timers.h [deleted file]
include/asm-blackfin/bfin-global.h
include/asm-blackfin/dma.h
include/asm-blackfin/gpio.h
include/asm-blackfin/gptimers.h [new file with mode: 0644]
include/asm-blackfin/mach-bf527/anomaly.h
include/asm-blackfin/mach-bf527/bf527.h [new file with mode: 0644]
include/asm-blackfin/mach-bf527/bfin_serial_5xx.h [new file with mode: 0644]
include/asm-blackfin/mach-bf527/blackfin.h [new file with mode: 0644]
include/asm-blackfin/mach-bf527/cdefBF52x_base.h
include/asm-blackfin/mach-bf527/defBF527.h
include/asm-blackfin/mach-bf527/defBF52x_base.h
include/asm-blackfin/mach-bf527/dma.h [new file with mode: 0644]
include/asm-blackfin/mach-bf527/irq.h [new file with mode: 0644]
include/asm-blackfin/mach-bf527/mem_init.h [new file with mode: 0644]
include/asm-blackfin/mach-bf527/mem_map.h [new file with mode: 0644]
include/asm-blackfin/mach-bf527/portmux.h [new file with mode: 0644]
include/asm-blackfin/mach-bf548/defBF549.h
include/asm-blackfin/mach-bf548/defBF54x_base.h
include/asm-blackfin/mach-bf548/dma.h
include/asm-blackfin/scatterlist.h
include/asm-cris/scatterlist.h
include/asm-frv/scatterlist.h
include/asm-h8300/scatterlist.h
include/asm-ia64/scatterlist.h
include/asm-m32r/scatterlist.h
include/asm-m68k/scatterlist.h
include/asm-m68knommu/module.h
include/asm-m68knommu/scatterlist.h
include/asm-m68knommu/uaccess.h
include/asm-mips/gt64120.h
include/asm-mips/i8253.h
include/asm-mips/scatterlist.h
include/asm-mips/sibyte/sb1250.h
include/asm-parisc/Kbuild
include/asm-parisc/io.h
include/asm-parisc/page.h
include/asm-parisc/pci.h
include/asm-parisc/pdc.h
include/asm-parisc/pgtable.h
include/asm-parisc/prefetch.h
include/asm-parisc/rtc.h
include/asm-parisc/scatterlist.h
include/asm-parisc/semaphore.h
include/asm-parisc/unistd.h
include/asm-powerpc/dma-mapping.h
include/asm-powerpc/mpc52xx.h
include/asm-powerpc/scatterlist.h
include/asm-ppc/system.h
include/asm-s390/cpu.h [new file with mode: 0644]
include/asm-s390/mmu_context.h
include/asm-s390/page.h
include/asm-s390/pgalloc.h
include/asm-s390/pgtable.h
include/asm-s390/processor.h
include/asm-s390/scatterlist.h
include/asm-s390/tlb.h
include/asm-s390/tlbflush.h
include/asm-sh/dma-mapping.h
include/asm-sh/scatterlist.h
include/asm-sh64/dma-mapping.h
include/asm-sh64/scatterlist.h
include/asm-sparc/scatterlist.h
include/asm-sparc64/scatterlist.h
include/asm-v850/scatterlist.h
include/asm-x86/Kbuild
include/asm-x86/bootparam.h
include/asm-x86/cacheflush.h
include/asm-x86/device.h
include/asm-x86/dma-mapping_32.h
include/asm-x86/e820.h
include/asm-x86/e820_32.h
include/asm-x86/e820_64.h
include/asm-x86/ist.h
include/asm-x86/lguest.h [new file with mode: 0644]
include/asm-x86/lguest_hcall.h [new file with mode: 0644]
include/asm-x86/scatterlist_32.h
include/asm-x86/scatterlist_64.h
include/asm-xtensa/dma-mapping.h
include/asm-xtensa/scatterlist.h
include/linux/Kbuild
include/linux/apm_bios.h
include/linux/audit.h
include/linux/capability.h
include/linux/dcache.h
include/linux/dmar.h [new file with mode: 0644]
include/linux/edd.h
include/linux/efi.h
include/linux/efs_fs.h
include/linux/exportfs.h
include/linux/ext2_fs.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/i8042.h [new file with mode: 0644]
include/linux/ide.h
include/linux/inotify.h
include/linux/lguest.h
include/linux/lguest_bus.h [deleted file]
include/linux/lguest_launcher.h
include/linux/linkage.h
include/linux/memory.h
include/linux/mlx4/doorbell.h
include/linux/mod_devicetable.h
include/linux/net.h
include/linux/netdevice.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/reiserfs_fs.h
include/linux/scatterlist.h
include/linux/screen_info.h
include/linux/skbuff.h
include/linux/socket.h
include/linux/videodev.h
include/linux/videodev2.h
include/linux/virtio.h [new file with mode: 0644]
include/linux/virtio_9p.h [new file with mode: 0644]
include/linux/virtio_blk.h [new file with mode: 0644]
include/linux/virtio_config.h [new file with mode: 0644]
include/linux/virtio_console.h [new file with mode: 0644]
include/linux/virtio_net.h [new file with mode: 0644]
include/linux/virtio_ring.h [new file with mode: 0644]
include/media/saa7146.h
include/media/v4l2-dev.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/sound/version.h
include/video/Kbuild
include/video/edid.h
init/Kconfig
ipc/mqueue.c
kernel/Makefile
kernel/audit.c
kernel/audit.h
kernel/audit_tree.c [new file with mode: 0644]
kernel/auditfilter.c
kernel/auditsc.c
kernel/irq/manage.c
kernel/sched.c
kernel/sysctl_check.c
lib/Kconfig.debug
lib/reed_solomon/decode_rs.c
lib/reed_solomon/reed_solomon.c
lib/swiotlb.c
mm/memory_hotplug.c
mm/mmap.c
mm/mprotect.c
mm/oom_kill.c
mm/shmem.c
mm/slub.c
net/9p/Kconfig
net/9p/Makefile
net/9p/trans_virtio.c [new file with mode: 0644]
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/core/dev.c
net/core/neighbour.c
net/core/netpoll.c
net/core/pktgen.c
net/core/skbuff.c
net/dccp/diag.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/ieee80211/ieee80211_crypt_tkip.c
net/ieee80211/ieee80211_crypt_wep.c
net/ipv4/inet_diag.c
net/ipv4/tcp_diag.c
net/ipv6/ah6.c
net/ipv6/esp6.c
net/mac80211/wep.c
net/sched/sch_teql.c
net/sctp/auth.c
net/sctp/sm_make_chunk.c
net/sunrpc/auth_gss/gss_krb5_crypto.c
net/sunrpc/xdr.c
net/xfrm/xfrm_algo.c
scripts/checkstack.pl
scripts/kconfig/qconf.cc
scripts/mod/file2alias.c
security/commoncap.c
security/selinux/hooks.c
sound/core/control.c
sound/i2c/other/tea575x-tuner.c
sound/pci/bt87x.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_local.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/sh/aica.c
sound/sparc/cs4231.c
sound/usb/usbquirks.h

diff --git a/Documentation/Intel-IOMMU.txt b/Documentation/Intel-IOMMU.txt
new file mode 100644 (file)
index 0000000..c232190
--- /dev/null
@@ -0,0 +1,115 @@
+Linux IOMMU Support
+===================
+
+The architecture spec can be obtained from the below location.
+
+http://www.intel.com/technology/virtualization/
+
+This guide gives a quick cheat sheet for some basic understanding.
+
+Some Keywords
+
+DMAR - DMA remapping
+DRHD - DMA Engine Reporting Structure
+RMRR - Reserved memory Region Reporting Structure
+ZLR  - Zero length reads from PCI devices
+IOVA - IO Virtual address.
+
+Basic stuff
+-----------
+
+ACPI enumerates and lists the different DMA engines in the platform, and
+device scope relationships between PCI devices and which DMA engine  controls
+them.
+
+What is RMRR?
+-------------
+
+There are some devices the BIOS controls, for e.g USB devices to perform
+PS2 emulation. The regions of memory used for these devices are marked
+reserved in the e820 map. When we turn on DMA translation, DMA to those
+regions will fail. Hence BIOS uses RMRR to specify these regions along with
+devices that need to access these regions. OS is expected to setup
+unity mappings for these regions for these devices to access these regions.
+
+How is IOVA generated?
+---------------------
+
+Well behaved drivers call pci_map_*() calls before sending command to device
+that needs to perform DMA. Once DMA is completed and mapping is no longer
+required, device performs a pci_unmap_*() calls to unmap the region.
+
+The Intel IOMMU driver allocates a virtual address per domain. Each PCIE
+device has its own domain (hence protection). Devices under p2p bridges
+share the virtual address with all devices under the p2p bridge due to
+transaction id aliasing for p2p bridges.
+
+IOVA generation is pretty generic. We used the same technique as vmalloc()
+but these are not global address spaces, but separate for each domain.
+Different DMA engines may support different number of domains.
+
+We also allocate gaurd pages with each mapping, so we can attempt to catch
+any overflow that might happen.
+
+
+Graphics Problems?
+------------------
+If you encounter issues with graphics devices, you can try adding
+option intel_iommu=igfx_off to turn off the integrated graphics engine.
+
+If it happens to be a PCI device included in the INCLUDE_ALL Engine,
+then try enabling CONFIG_DMAR_GFX_WA to setup a 1-1 map. We hear
+graphics drivers may be in process of using DMA api's in the near
+future and at that time this option can be yanked out.
+
+Some exceptions to IOVA
+-----------------------
+Interrupt ranges are not address translated, (0xfee00000 - 0xfeefffff).
+The same is true for peer to peer transactions. Hence we reserve the
+address from PCI MMIO ranges so they are not allocated for IOVA addresses.
+
+
+Fault reporting
+---------------
+When errors are reported, the DMA engine signals via an interrupt. The fault
+reason and device that caused it with fault reason is printed on console.
+
+See below for sample.
+
+
+Boot Message Sample
+-------------------
+
+Something like this gets printed indicating presence of DMAR tables
+in ACPI.
+
+ACPI: DMAR (v001 A M I  OEMDMAR  0x00000001 MSFT 0x00000097) @ 0x000000007f5b5ef0
+
+When DMAR is being processed and initialized by ACPI, prints DMAR locations
+and any RMRR's processed.
+
+ACPI DMAR:Host address width 36
+ACPI DMAR:DRHD (flags: 0x00000000)base: 0x00000000fed90000
+ACPI DMAR:DRHD (flags: 0x00000000)base: 0x00000000fed91000
+ACPI DMAR:DRHD (flags: 0x00000001)base: 0x00000000fed93000
+ACPI DMAR:RMRR base: 0x00000000000ed000 end: 0x00000000000effff
+ACPI DMAR:RMRR base: 0x000000007f600000 end: 0x000000007fffffff
+
+When DMAR is enabled for use, you will notice..
+
+PCI-DMA: Using DMAR IOMMU
+
+Fault reporting
+---------------
+
+DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000
+DMAR:[fault reason 05] PTE Write access is not set
+DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000
+DMAR:[fault reason 05] PTE Write access is not set
+
+TBD
+----
+
+- For compatibility testing, could use unity map domain for all devices, just
+  provide a 1-1 for all useful memory under a single domain for all devices.
+- API for paravirt ops for abstracting functionlity for VMM folks.
index 6b0f963..6bb9be5 100644 (file)
@@ -14,18 +14,6 @@ Who: Jiri Slaby <jirislaby@gmail.com>
 
 ---------------------------
 
-What:  V4L2 VIDIOC_G_MPEGCOMP and VIDIOC_S_MPEGCOMP
-When:  October 2007
-Why:   Broken attempt to set MPEG compression parameters. These ioctls are
-       not able to implement the wide variety of parameters that can be set
-       by hardware MPEG encoders. A new MPEG control mechanism was created
-       in kernel 2.6.18 that replaces these ioctls. See the V4L2 specification
-       (section 1.9: Extended controls) for more information on this topic.
-Who:   Hans Verkuil <hverkuil@xs4all.nl> and
-       Mauro Carvalho Chehab <mchehab@infradead.org>
-
----------------------------
-
 What:  dev->power.power_state
 When:  July 2007
 Why:   Broken design for runtime control over driver power states, confusing
@@ -49,10 +37,10 @@ Who:        David Miller <davem@davemloft.net>
 ---------------------------
 
 What:  Video4Linux API 1 ioctls and video_decoder.h from Video devices.
-When:  December 2006
-Files: include/linux/video_decoder.h
-Check: include/linux/video_decoder.h
-Why:   V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
+When:  December 2008
+Files: include/linux/video_decoder.h include/linux/videodev.h
+Check: include/linux/video_decoder.h include/linux/videodev.h
+Why:   V4L1 AP1 was replaced by V4L2 API during migration from 2.4 to 2.6
        series. The old API have lots of drawbacks and don't provide enough
        means to work with all video and audio standards. The newer API is
        already available on the main drivers and should be used instead.
@@ -61,7 +49,9 @@ Why:  V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
        Decoder iocts are using internally to allow video drivers to
        communicate with video decoders. This should also be improved to allow
        V4L2 calls being translated into compatible internal ioctls.
-Who:   Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+       Compatibility ioctls will be provided, for a while, via 
+       v4l1-compat module. 
+Who:   Mauro Carvalho Chehab <mchehab@infradead.org>
 
 ---------------------------
 
index b90f537..bf80806 100644 (file)
@@ -42,10 +42,12 @@ OPTIONS
 
   trans=name   select an alternative transport.  Valid options are
                currently:
-                       unix - specifying a named pipe mount point
-                       tcp  - specifying a normal TCP/IP connection
-                       fd   - used passed file descriptors for connection
+                       unix    - specifying a named pipe mount point
+                       tcp     - specifying a normal TCP/IP connection
+                       fd      - used passed file descriptors for connection
                                 (see rfdno and wfdno)
+                       virtio  - connect to the next virtio channel available
+                               (from lguest or KVM with trans_virtio module)
 
   uname=name   user name to attempt mount as on the remote server.  The
                server may override or ignore this value.  Certain user
index 31047e0..87019d2 100644 (file)
@@ -2,9 +2,12 @@
 Making Filesystems Exportable
 =============================
 
-Most filesystem operations require a dentry (or two) as a starting
+Overview
+--------
+
+All filesystem operations require a dentry (or two) as a starting
 point.  Local applications have a reference-counted hold on suitable
-dentrys via open file descriptors or cwd/root.  However remote
+dentries via open file descriptors or cwd/root.  However remote
 applications that access a filesystem via a remote filesystem protocol
 such as NFS may not be able to hold such a reference, and so need a
 different way to refer to a particular dentry.  As the alternative
@@ -13,14 +16,14 @@ server-reboot (among other things, though these tend to be the most
 problematic), there is no simple answer like 'filename'.
 
 The mechanism discussed here allows each filesystem implementation to
-specify how to generate an opaque (out side of the filesystem) byte
+specify how to generate an opaque (outside of the filesystem) byte
 string for any dentry, and how to find an appropriate dentry for any
 given opaque byte string.
 This byte string will be called a "filehandle fragment" as it
 corresponds to part of an NFS filehandle.
 
 A filesystem which supports the mapping between filehandle fragments
-and dentrys will be termed "exportable".
+and dentries will be termed "exportable".
 
 
 
@@ -89,11 +92,9 @@ For a filesystem to be exportable it must:
    1/ provide the filehandle fragment routines described below.
    2/ make sure that d_splice_alias is used rather than d_add
       when ->lookup finds an inode for a given parent and name.
-      Typically the ->lookup routine will end:
-               if (inode)
-                       return d_splice(inode, dentry);
-               d_add(dentry, inode);
-               return NULL;
+      Typically the ->lookup routine will end with a:
+
+               return d_splice_alias(inode, dentry);
        }
 
 
@@ -101,67 +102,39 @@ For a filesystem to be exportable it must:
   A file system implementation declares that instances of the filesystem
 are exportable by setting the s_export_op field in the struct
 super_block.  This field must point to a "struct export_operations"
-struct which could potentially be full of NULLs, though normally at
-least get_parent will be set.
-
- The primary operations are decode_fh and encode_fh.  
-decode_fh takes a filehandle fragment and tries to find or create a
-dentry for the object referred to by the filehandle.
-encode_fh takes a dentry and creates a filehandle fragment which can
-later be used to find/create a dentry for the same object.
-
-decode_fh will probably make use of "find_exported_dentry".
-This function lives in the "exportfs" module which a filesystem does
-not need unless it is being exported.  So rather that calling
-find_exported_dentry directly, each filesystem should call it through
-the find_exported_dentry pointer in it's export_operations table.
-This field is set correctly by the exporting agent (e.g. nfsd) when a
-filesystem is exported, and before any export operations are called.
-
-find_exported_dentry needs three support functions from the
-filesystem:
-  get_name.  When given a parent dentry and a child dentry, this
-    should find a name in the directory identified by the parent
-    dentry, which leads to the object identified by the child dentry.
-    If no get_name function is supplied, a default implementation is
-    provided which uses vfs_readdir to find potential names, and
-    matches inode numbers to find the correct match.
-
-  get_parent.  When given a dentry for a directory, this should return 
-    a dentry for the parent.  Quite possibly the parent dentry will
-    have been allocated by d_alloc_anon.  
-    The default get_parent function just returns an error so any
-    filehandle lookup that requires finding a parent will fail.
-    ->lookup("..") is *not* used as a default as it can leave ".."
-    entries in the dcache which are too messy to work with.
-
-  get_dentry.  When given an opaque datum, this should find the
-    implied object and create a dentry for it (possibly with
-    d_alloc_anon). 
-    The opaque datum is whatever is passed down by the decode_fh
-    function, and is often simply a fragment of the filehandle
-    fragment.
-    decode_fh passes two datums through find_exported_dentry.  One that 
-    should be used to identify the target object, and one that can be
-    used to identify the object's parent, should that be necessary.
-    The default get_dentry function assumes that the datum contains an
-    inode number and a generation number, and it attempts to get the
-    inode using "iget" and check it's validity by matching the
-    generation number.  A filesystem should only depend on the default
-    if iget can safely be used this way.
-
-If decode_fh and/or encode_fh are left as NULL, then default
-implementations are used.  These defaults are suitable for ext2 and 
-extremely similar filesystems (like ext3).
-
-The default encode_fh creates a filehandle fragment from the inode
-number and generation number of the target together with the inode
-number and generation number of the parent (if the parent is
-required).
-
-The default decode_fh extract the target and parent datums from the
-filehandle assuming the format used by the default encode_fh and
-passed them to find_exported_dentry.
+struct which has the following members:
+
+ encode_fh  (optional)
+    Takes a dentry and creates a filehandle fragment which can later be used
+    to find or create a dentry for the same object.  The default
+    implementation creates a filehandle fragment that encodes a 32bit inode
+    and generation number for the inode encoded, and if necessary the
+    same information for the parent.
+
+  fh_to_dentry (mandatory)
+    Given a filehandle fragment, this should find the implied object and
+    create a dentry for it (possibly with d_alloc_anon).
+
+  fh_to_parent (optional but strongly recommended)
+    Given a filehandle fragment, this should find the parent of the
+    implied object and create a dentry for it (possibly with d_alloc_anon).
+    May fail if the filehandle fragment is too small.
+
+  get_parent (optional but strongly recommended)
+    When given a dentry for a directory, this should return  a dentry for
+    the parent.  Quite possibly the parent dentry will have been allocated
+    by d_alloc_anon.  The default get_parent function just returns an error
+    so any filehandle lookup that requires finding a parent will fail.
+    ->lookup("..") is *not* used as a default as it can leave ".." entries
+    in the dcache which are too messy to work with.
+
+  get_name (optional)
+    When given a parent dentry and a child dentry, this should find a name
+    in the directory identified by the parent dentry, which leads to the
+    object identified by the child dentry.  If no get_name function is
+    supplied, a default implementation is provided which uses vfs_readdir
+    to find potential names, and matches inode numbers to find the correct
+    match.
 
 
 A filehandle fragment consists of an array of 1 or more 4byte words,
@@ -172,5 +145,3 @@ generated by encode_fh, in which case it will have been padded with
 nuls.  Rather, the encode_fh routine should choose a "type" which
 indicates the decode_fh how much of the filehandle is valid, and how
 it should be interpreted.
-
index 35985b3..2f75e75 100644 (file)
@@ -168,6 +168,8 @@ Offset      Proto   Name            Meaning
 0234/1 2.05+   relocatable_kernel Whether kernel is relocatable or not
 0235/3 N/A     pad2            Unused
 0238/4 2.06+   cmdline_size    Maximum size of the kernel command line
+023C/4 2.07+   hardware_subarch Hardware subarchitecture
+0240/8 2.07+   hardware_subarch_data Subarchitecture-specific data
 
 (1) For backwards compatibility, if the setup_sects field contains 0, the
     real value is 4.
@@ -204,7 +206,7 @@ boot loaders can ignore those fields.
 
 The byte order of all fields is littleendian (this is x86, after all.)
 
-Field name:    setup_secs
+Field name:    setup_sects
 Type:          read
 Offset/size:   0x1f1/1
 Protocol:      ALL
@@ -356,6 +358,13 @@ Protocol:  2.00+
        - If 0, the protected-mode code is loaded at 0x10000.
        - If 1, the protected-mode code is loaded at 0x100000.
 
+  Bit 6 (write): KEEP_SEGMENTS
+       Protocol: 2.07+
+       - if 0, reload the segment registers in the 32bit entry point.
+       - if 1, do not reload the segment registers in the 32bit entry point.
+               Assume that %cs %ds %ss %es are all set to flat segments with
+               a base of 0 (or the equivalent for their environment).
+
   Bit 7 (write): CAN_USE_HEAP
        Set this bit to 1 to indicate that the value entered in the
        heap_end_ptr is valid.  If this field is clear, some setup code
@@ -480,6 +489,29 @@ Protocol:  2.06+
   cmdline_size characters. With protocol version 2.05 and earlier, the
   maximum size was 255.
 
+Field name:    hardware_subarch
+Type:          write
+Offset/size:   0x23c/4
+Protocol:      2.07+
+
+  In a paravirtualized environment the hardware low level architectural
+  pieces such as interrupt handling, page table handling, and
+  accessing process control registers needs to be done differently.
+
+  This field allows the bootloader to inform the kernel we are in one
+  one of those environments.
+
+  0x00000000   The default x86/PC environment
+  0x00000001   lguest
+  0x00000002   Xen
+
+Field name:    hardware_subarch_data
+Type:          write
+Offset/size:   0x240/8
+Protocol:      2.07+
+
+  A pointer to data that is specific to hardware subarch
+
 
 **** THE KERNEL COMMAND LINE
 
index 6166e2d..7a77533 100644 (file)
@@ -519,17 +519,17 @@ more details, with real examples.
        to the user why it stops.
 
     cc-cross-prefix
-       cc-cross-prefix is used to check if there exist a $(CC) in path with
+       cc-cross-prefix is used to check if there exists a $(CC) in path with
        one of the listed prefixes. The first prefix where there exist a
        prefix$(CC) in the PATH is returned - and if no prefix$(CC) is found
        then nothing is returned.
        Additional prefixes are separated by a single space in the
        call of cc-cross-prefix.
-       This functionality is usefull for architecture Makefile that try
-       to set CROSS_COMPILE to well know values but may have several
+       This functionality is useful for architecture Makefiles that try
+       to set CROSS_COMPILE to well-known values but may have several
        values to select between.
-       It is recommended only to try to set CROSS_COMPILE is it is a cross
-       build (host arch is different from target arch). And is CROSS_COMPILE
+       It is recommended only to try to set CROSS_COMPILE if it is a cross
+       build (host arch is different from target arch). And if CROSS_COMPILE
        is already set then leave it with the old value.
 
        Example:
index 6accd36..b236166 100644 (file)
@@ -772,6 +772,23 @@ and is between 256 and 4096 characters. It is defined in the file
 
        inttest=        [IA64]
 
+       intel_iommu=    [DMAR] Intel IOMMU driver (DMAR) option
+               off
+                       Disable intel iommu driver.
+               igfx_off [Default Off]
+                       By default, gfx is mapped as normal device. If a gfx
+                       device has a dedicated DMAR unit, the DMAR unit is
+                       bypassed by not enabling DMAR with this option. In
+                       this case, gfx device will use physical address for
+                       DMA.
+               forcedac [x86_64]
+                       With this option iommu will not optimize to look
+                       for io virtual address below 32 bit forcing dual
+                       address cycle on pci bus for cards supporting greater
+                       than 32 bit addressing. The default is to look
+                       for translation below 32 bit and if not available
+                       then look in the higher range.
+
        io7=            [HW] IO7 for Marvel based alpha systems
                        See comment before marvel_specify_io7 in
                        arch/alpha/kernel/core_marvel.c.
index c0b7a45..bac037e 100644 (file)
@@ -1,28 +1,8 @@
 # This creates the demonstration utility "lguest" which runs a Linux guest.
-
-# For those people that have a separate object dir, look there for .config
-KBUILD_OUTPUT := ../..
-ifdef O
-  ifeq ("$(origin O)", "command line")
-    KBUILD_OUTPUT := $(O)
-  endif
-endif
-# We rely on CONFIG_PAGE_OFFSET to know where to put lguest binary.
-include $(KBUILD_OUTPUT)/.config
-LGUEST_GUEST_TOP := ($(CONFIG_PAGE_OFFSET) - 0x08000000)
-
-CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 -Wl,-T,lguest.lds
+CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 -I../../include
 LDLIBS:=-lz
-# Removing this works for some versions of ld.so (eg. Ubuntu Feisty) and
-# not others (eg. FC7).
-LDFLAGS+=-static
-all: lguest.lds lguest
 
-# The linker script on x86 is so complex the only way of creating one
-# which will link our binary in the right place is to mangle the
-# default one.
-lguest.lds:
-       $(LD) --verbose | awk '/^==========/ { PRINT=1; next; } /SIZEOF_HEADERS/ { gsub(/0x[0-9A-F]*/, "$(LGUEST_GUEST_TOP)") } { if (PRINT) print $$0; }' > $@
+all: lguest
 
 clean:
-       rm -f lguest.lds lguest
+       rm -f lguest
index 103e346..5bdc37f 100644 (file)
@@ -1,10 +1,7 @@
 /*P:100 This is the Launcher code, a simple program which lays out the
  * "physical" memory for the new Guest by mapping the kernel image and the
  * virtual devices, then reads repeatedly from /dev/lguest to run the Guest.
- *
- * The only trick: the Makefile links it at a high address so it will be clear
- * of the guest memory region.  It means that each Guest cannot have more than
- * about 2.5G of memory on a normally configured Host. :*/
+:*/
 #define _LARGEFILE64_SOURCE
 #define _GNU_SOURCE
 #include <stdio.h>
@@ -15,6 +12,7 @@
 #include <stdlib.h>
 #include <elf.h>
 #include <sys/mman.h>
+#include <sys/param.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
@@ -34,7 +32,9 @@
 #include <termios.h>
 #include <getopt.h>
 #include <zlib.h>
-/*L:110 We can ignore the 28 include files we need for this program, but I do
+#include <assert.h>
+#include <sched.h>
+/*L:110 We can ignore the 30 include files we need for this program, but I do
  * want to draw attention to the use of kernel-style types.
  *
  * As Linus said, "C is a Spartan language, and so should your naming be."  I
@@ -45,8 +45,14 @@ typedef unsigned long long u64;
 typedef uint32_t u32;
 typedef uint16_t u16;
 typedef uint8_t u8;
-#include "../../include/linux/lguest_launcher.h"
-#include "../../include/asm-x86/e820_32.h"
+#include "linux/lguest_launcher.h"
+#include "linux/pci_ids.h"
+#include "linux/virtio_config.h"
+#include "linux/virtio_net.h"
+#include "linux/virtio_blk.h"
+#include "linux/virtio_console.h"
+#include "linux/virtio_ring.h"
+#include "asm-x86/bootparam.h"
 /*:*/
 
 #define PAGE_PRESENT 0x7       /* Present, RW, Execute */
@@ -55,6 +61,10 @@ typedef uint8_t u8;
 #ifndef SIOCBRADDIF
 #define SIOCBRADDIF    0x89a2          /* add interface to bridge      */
 #endif
+/* We can have up to 256 pages for devices. */
+#define DEVICE_PAGES 256
+/* This fits nicely in a single 4096-byte page. */
+#define VIRTQUEUE_NUM 127
 
 /*L:120 verbose is both a global flag and a macro.  The C preprocessor allows
  * this, and although I wouldn't recommend it, it works quite nicely here. */
@@ -65,8 +75,10 @@ static bool verbose;
 
 /* The pipe to send commands to the waker process */
 static int waker_fd;
-/* The top of guest physical memory. */
-static u32 top;
+/* The pointer to the start of guest memory. */
+static void *guest_base;
+/* The maximum guest physical address allowed, and maximum possible. */
+static unsigned long guest_limit, guest_max;
 
 /* This is our list of devices. */
 struct device_list
@@ -76,8 +88,17 @@ struct device_list
        fd_set infds;
        int max_infd;
 
+       /* Counter to assign interrupt numbers. */
+       unsigned int next_irq;
+
+       /* Counter to print out convenient device numbers. */
+       unsigned int device_num;
+
        /* The descriptor page for the devices. */
-       struct lguest_device_desc *descs;
+       u8 *descpage;
+
+       /* The tail of the last descriptor. */
+       unsigned int desc_used;
 
        /* A single linked list of devices. */
        struct device *dev;
@@ -85,31 +106,111 @@ struct device_list
        struct device **lastdev;
 };
 
+/* The list of Guest devices, based on command line arguments. */
+static struct device_list devices;
+
 /* The device structure describes a single device. */
 struct device
 {
        /* The linked-list pointer. */
        struct device *next;
-       /* The descriptor for this device, as mapped into the Guest. */
+
+       /* The this device's descriptor, as mapped into the Guest. */
        struct lguest_device_desc *desc;
-       /* The memory page(s) of this device, if any.  Also mapped in Guest. */
-       void *mem;
+
+       /* The name of this device, for --verbose. */
+       const char *name;
 
        /* If handle_input is set, it wants to be called when this file
         * descriptor is ready. */
        int fd;
        bool (*handle_input)(int fd, struct device *me);
 
-       /* If handle_output is set, it wants to be called when the Guest sends
-        * DMA to this key. */
-       unsigned long watch_key;
-       u32 (*handle_output)(int fd, const struct iovec *iov,
-                            unsigned int num, struct device *me);
+       /* Any queues attached to this device */
+       struct virtqueue *vq;
 
        /* Device-specific data. */
        void *priv;
 };
 
+/* The virtqueue structure describes a queue attached to a device. */
+struct virtqueue
+{
+       struct virtqueue *next;
+
+       /* Which device owns me. */
+       struct device *dev;
+
+       /* The configuration for this queue. */
+       struct lguest_vqconfig config;
+
+       /* The actual ring of buffers. */
+       struct vring vring;
+
+       /* Last available index we saw. */
+       u16 last_avail_idx;
+
+       /* The routine to call when the Guest pings us. */
+       void (*handle_output)(int fd, struct virtqueue *me);
+};
+
+/* Since guest is UP and we don't run at the same time, we don't need barriers.
+ * But I include them in the code in case others copy it. */
+#define wmb()
+
+/* Convert an iovec element to the given type.
+ *
+ * This is a fairly ugly trick: we need to know the size of the type and
+ * alignment requirement to check the pointer is kosher.  It's also nice to
+ * have the name of the type in case we report failure.
+ *
+ * Typing those three things all the time is cumbersome and error prone, so we
+ * have a macro which sets them all up and passes to the real function. */
+#define convert(iov, type) \
+       ((type *)_convert((iov), sizeof(type), __alignof__(type), #type))
+
+static void *_convert(struct iovec *iov, size_t size, size_t align,
+                     const char *name)
+{
+       if (iov->iov_len != size)
+               errx(1, "Bad iovec size %zu for %s", iov->iov_len, name);
+       if ((unsigned long)iov->iov_base % align != 0)
+               errx(1, "Bad alignment %p for %s", iov->iov_base, name);
+       return iov->iov_base;
+}
+
+/* The virtio configuration space is defined to be little-endian.  x86 is
+ * little-endian too, but it's nice to be explicit so we have these helpers. */
+#define cpu_to_le16(v16) (v16)
+#define cpu_to_le32(v32) (v32)
+#define cpu_to_le64(v64) (v64)
+#define le16_to_cpu(v16) (v16)
+#define le32_to_cpu(v32) (v32)
+#define le64_to_cpu(v32) (v64)
+
+/*L:100 The Launcher code itself takes us out into userspace, that scary place
+ * where pointers run wild and free!  Unfortunately, like most userspace
+ * programs, it's quite boring (which is why everyone likes to hack on the
+ * kernel!).  Perhaps if you make up an Lguest Drinking Game at this point, it
+ * will get you through this section.  Or, maybe not.
+ *
+ * The Launcher sets up a big chunk of memory to be the Guest's "physical"
+ * memory and stores it in "guest_base".  In other words, Guest physical ==
+ * Launcher virtual with an offset.
+ *
+ * This can be tough to get your head around, but usually it just means that we
+ * use these trivial conversion functions when the Guest gives us it's
+ * "physical" addresses: */
+static void *from_guest_phys(unsigned long addr)
+{
+       return guest_base + addr;
+}
+
+static unsigned long to_guest_phys(const void *addr)
+{
+       return (addr - guest_base);
+}
+
 /*L:130
  * Loading the Kernel.
  *
@@ -123,43 +224,55 @@ static int open_or_die(const char *name, int flags)
        return fd;
 }
 
-/* map_zeroed_pages() takes a (page-aligned) address and a number of pages. */
-static void *map_zeroed_pages(unsigned long addr, unsigned int num)
+/* map_zeroed_pages() takes a number of pages. */
+static void *map_zeroed_pages(unsigned int num)
 {
-       /* We cache the /dev/zero file-descriptor so we only open it once. */
-       static int fd = -1;
-
-       if (fd == -1)
-               fd = open_or_die("/dev/zero", O_RDONLY);
+       int fd = open_or_die("/dev/zero", O_RDONLY);
+       void *addr;
 
        /* We use a private mapping (ie. if we write to the page, it will be
-        * copied), and obviously we insist that it be mapped where we ask. */
-       if (mmap((void *)addr, getpagesize() * num,
-                PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0)
-           != (void *)addr)
-               err(1, "Mmaping %u pages of /dev/zero @%p", num, (void *)addr);
-
-       /* Returning the address is just a courtesy: can simplify callers. */
-       return (void *)addr;
+        * copied). */
+       addr = mmap(NULL, getpagesize() * num,
+                   PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
+       if (addr == MAP_FAILED)
+               err(1, "Mmaping %u pages of /dev/zero", num);
+
+       return addr;
 }
 
-/* To find out where to start we look for the magic Guest string, which marks
- * the code we see in lguest_asm.S.  This is a hack which we are currently
- * plotting to replace with the normal Linux entry point. */
-static unsigned long entry_point(void *start, void *end,
-                                unsigned long page_offset)
+/* Get some more pages for a device. */
+static void *get_pages(unsigned int num)
 {
-       void *p;
+       void *addr = from_guest_phys(guest_limit);
 
-       /* The scan gives us the physical starting address.  We want the
-        * virtual address in this case, and fortunately, we already figured
-        * out the physical-virtual difference and passed it here in
-        * "page_offset". */
-       for (p = start; p < end; p++)
-               if (memcmp(p, "GenuineLguest", strlen("GenuineLguest")) == 0)
-                       return (long)p + strlen("GenuineLguest") + page_offset;
+       guest_limit += num * getpagesize();
+       if (guest_limit > guest_max)
+               errx(1, "Not enough memory for devices");
+       return addr;
+}
 
-       err(1, "Is this image a genuine lguest?");
+/* This routine is used to load the kernel or initrd.  It tries mmap, but if
+ * that fails (Plan 9's kernel file isn't nicely aligned on page boundaries),
+ * it falls back to reading the memory in. */
+static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
+{
+       ssize_t r;
+
+       /* We map writable even though for some segments are marked read-only.
+        * The kernel really wants to be writable: it patches its own
+        * instructions.
+        *
+        * MAP_PRIVATE means that the page won't be copied until a write is
+        * done to it.  This allows us to share untouched memory between
+        * Guests. */
+       if (mmap(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC,
+                MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED)
+               return;
+
+       /* pread does a seek and a read in one shot: saves a few lines. */
+       r = pread(fd, addr, len, offset);
+       if (r != len)
+               err(1, "Reading offset %lu len %lu gave %zi", offset, len, r);
 }
 
 /* This routine takes an open vmlinux image, which is in ELF, and maps it into
@@ -167,19 +280,14 @@ static unsigned long entry_point(void *start, void *end,
  * by all modern binaries on Linux including the kernel.
  *
  * The ELF headers give *two* addresses: a physical address, and a virtual
- * address.  The Guest kernel expects to be placed in memory at the physical
- * address, and the page tables set up so it will correspond to that virtual
- * address.  We return the difference between the virtual and physical
- * addresses in the "page_offset" pointer.
+ * address.  We use the physical address; the Guest will map itself to the
+ * virtual address.
  *
  * We return the starting address. */
-static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
-                            unsigned long *page_offset)
+static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
 {
-       void *addr;
        Elf32_Phdr phdr[ehdr->e_phnum];
        unsigned int i;
-       unsigned long start = -1UL, end = 0;
 
        /* Sanity checks on the main ELF header: an x86 executable with a
         * reasonable number of correctly-sized program headers. */
@@ -199,9 +307,6 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
        if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
                err(1, "Reading program headers");
 
-       /* We don't know page_offset yet. */
-       *page_offset = 0;
-
        /* Try all the headers: there are usually only three.  A read-only one,
         * a read-write one, and a "note" section which isn't loadable. */
        for (i = 0; i < ehdr->e_phnum; i++) {
@@ -212,158 +317,53 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
                verbose("Section %i: size %i addr %p\n",
                        i, phdr[i].p_memsz, (void *)phdr[i].p_paddr);
 
-               /* We expect a simple linear address space: every segment must
-                * have the same difference between virtual (p_vaddr) and
-                * physical (p_paddr) address. */
-               if (!*page_offset)
-                       *page_offset = phdr[i].p_vaddr - phdr[i].p_paddr;
-               else if (*page_offset != phdr[i].p_vaddr - phdr[i].p_paddr)
-                       errx(1, "Page offset of section %i different", i);
-
-               /* We track the first and last address we mapped, so we can
-                * tell entry_point() where to scan. */
-               if (phdr[i].p_paddr < start)
-                       start = phdr[i].p_paddr;
-               if (phdr[i].p_paddr + phdr[i].p_filesz > end)
-                       end = phdr[i].p_paddr + phdr[i].p_filesz;
-
-               /* We map this section of the file at its physical address.  We
-                * map it read & write even if the header says this segment is
-                * read-only.  The kernel really wants to be writable: it
-                * patches its own instructions which would normally be
-                * read-only.
-                *
-                * MAP_PRIVATE means that the page won't be copied until a
-                * write is done to it.  This allows us to share much of the
-                * kernel memory between Guests. */
-               addr = mmap((void *)phdr[i].p_paddr,
-                           phdr[i].p_filesz,
-                           PROT_READ|PROT_WRITE|PROT_EXEC,
-                           MAP_FIXED|MAP_PRIVATE,
-                           elf_fd, phdr[i].p_offset);
-               if (addr != (void *)phdr[i].p_paddr)
-                       err(1, "Mmaping vmlinux seg %i gave %p not %p",
-                           i, addr, (void *)phdr[i].p_paddr);
+               /* We map this section of the file at its physical address. */
+               map_at(elf_fd, from_guest_phys(phdr[i].p_paddr),
+                      phdr[i].p_offset, phdr[i].p_filesz);
        }
 
-       return entry_point((void *)start, (void *)end, *page_offset);
+       /* The entry point is given in the ELF header. */
+       return ehdr->e_entry;
 }
 
-/*L:170 Prepare to be SHOCKED and AMAZED.  And possibly a trifle nauseated.
- *
- * We know that CONFIG_PAGE_OFFSET sets what virtual address the kernel expects
- * to be.  We don't know what that option was, but we can figure it out
- * approximately by looking at the addresses in the code.  I chose the common
- * case of reading a memory location into the %eax register:
- *
- *  movl <some-address>, %eax
- *
- * This gets encoded as five bytes: "0xA1 <4-byte-address>".  For example,
- * "0xA1 0x18 0x60 0x47 0xC0" reads the address 0xC0476018 into %eax.
- *
- * In this example can guess that the kernel was compiled with
- * CONFIG_PAGE_OFFSET set to 0xC0000000 (it's always a round number).  If the
- * kernel were larger than 16MB, we might see 0xC1 addresses show up, but our
- * kernel isn't that bloated yet.
- *
- * Unfortunately, x86 has variable-length instructions, so finding this
- * particular instruction properly involves writing a disassembler.  Instead,
- * we rely on statistics.  We look for "0xA1" and tally the different bytes
- * which occur 4 bytes later (the "0xC0" in our example above).  When one of
- * those bytes appears three times, we can be reasonably confident that it
- * forms the start of CONFIG_PAGE_OFFSET.
+/*L:150 A bzImage, unlike an ELF file, is not meant to be loaded.  You're
+ * supposed to jump into it and it will unpack itself.  We used to have to
+ * perform some hairy magic because the unpacking code scared me.
  *
- * This is amazingly reliable. */
-static unsigned long intuit_page_offset(unsigned char *img, unsigned long len)
+ * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote
+ * a small patch to jump over the tricky bits in the Guest, so now we just read
+ * the funky header so we know where in the file to load, and away we go! */
+static unsigned long load_bzimage(int fd)
 {
-       unsigned int i, possibilities[256] = { 0 };
+       struct boot_params boot;
+       int r;
+       /* Modern bzImages get loaded at 1M. */
+       void *p = from_guest_phys(0x100000);
 
-       for (i = 0; i + 4 < len; i++) {
-               /* mov 0xXXXXXXXX,%eax */
-               if (img[i] == 0xA1 && ++possibilities[img[i+4]] > 3)
-                       return (unsigned long)img[i+4] << 24;
-       }
-       errx(1, "could not determine page offset");
-}
+       /* Go back to the start of the file and read the header.  It should be
+        * a Linux boot header (see Documentation/i386/boot.txt) */
+       lseek(fd, 0, SEEK_SET);
+       read(fd, &boot, sizeof(boot));
 
-/*L:160 Unfortunately the entire ELF image isn't compressed: the segments
- * which need loading are extracted and compressed raw.  This denies us the
- * information we need to make a fully-general loader. */
-static unsigned long unpack_bzimage(int fd, unsigned long *page_offset)
-{
-       gzFile f;
-       int ret, len = 0;
-       /* A bzImage always gets loaded at physical address 1M.  This is
-        * actually configurable as CONFIG_PHYSICAL_START, but as the comment
-        * there says, "Don't change this unless you know what you are doing".
-        * Indeed. */
-       void *img = (void *)0x100000;
-
-       /* gzdopen takes our file descriptor (carefully placed at the start of
-        * the GZIP header we found) and returns a gzFile. */
-       f = gzdopen(fd, "rb");
-       /* We read it into memory in 64k chunks until we hit the end. */
-       while ((ret = gzread(f, img + len, 65536)) > 0)
-               len += ret;
-       if (ret < 0)
-               err(1, "reading image from bzImage");
-
-       verbose("Unpacked size %i addr %p\n", len, img);
-
-       /* Without the ELF header, we can't tell virtual-physical gap.  This is
-        * CONFIG_PAGE_OFFSET, and people do actually change it.  Fortunately,
-        * I have a clever way of figuring it out from the code itself.  */
-       *page_offset = intuit_page_offset(img, len);
-
-       return entry_point(img, img + len, *page_offset);
-}
+       /* Inside the setup_hdr, we expect the magic "HdrS" */
+       if (memcmp(&boot.hdr.header, "HdrS", 4) != 0)
+               errx(1, "This doesn't look like a bzImage to me");
 
-/*L:150 A bzImage, unlike an ELF file, is not meant to be loaded.  You're
- * supposed to jump into it and it will unpack itself.  We can't do that
- * because the Guest can't run the unpacking code, and adding features to
- * lguest kills puppies, so we don't want to.
- *
- * The bzImage is formed by putting the decompressing code in front of the
- * compressed kernel code.  So we can simple scan through it looking for the
- * first "gzip" header, and start decompressing from there. */
-static unsigned long load_bzimage(int fd, unsigned long *page_offset)
-{
-       unsigned char c;
-       int state = 0;
-
-       /* GZIP header is 0x1F 0x8B <method> <flags>... <compressed-by>. */
-       while (read(fd, &c, 1) == 1) {
-               switch (state) {
-               case 0:
-                       if (c == 0x1F)
-                               state++;
-                       break;
-               case 1:
-                       if (c == 0x8B)
-                               state++;
-                       else
-                               state = 0;
-                       break;
-               case 2 ... 8:
-                       state++;
-                       break;
-               case 9:
-                       /* Seek back to the start of the gzip header. */
-                       lseek(fd, -10, SEEK_CUR);
-                       /* One final check: "compressed under UNIX". */
-                       if (c != 0x03)
-                               state = -1;
-                       else
-                               return unpack_bzimage(fd, page_offset);
-               }
-       }
-       errx(1, "Could not find kernel in bzImage");
+       /* Skip over the extra sectors of the header. */
+       lseek(fd, (boot.hdr.setup_sects+1) * 512, SEEK_SET);
+
+       /* Now read everything into memory. in nice big chunks. */
+       while ((r = read(fd, p, 65536)) > 0)
+               p += r;
+
+       /* Finally, code32_start tells us where to enter the kernel. */
+       return boot.hdr.code32_start;
 }
 
 /*L:140 Loading the kernel is easy when it's a "vmlinux", but most kernels
  * come wrapped up in the self-decompressing "bzImage" format.  With some funky
  * coding, we can load those, too. */
-static unsigned long load_kernel(int fd, unsigned long *page_offset)
+static unsigned long load_kernel(int fd)
 {
        Elf32_Ehdr hdr;
 
@@ -373,10 +373,10 @@ static unsigned long load_kernel(int fd, unsigned long *page_offset)
 
        /* If it's an ELF file, it starts with "\177ELF" */
        if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0)
-               return map_elf(fd, &hdr, page_offset);
+               return map_elf(fd, &hdr);
 
        /* Otherwise we assume it's a bzImage, and try to unpack it */
-       return load_bzimage(fd, page_offset);
+       return load_bzimage(fd);
 }
 
 /* This is a trivial little helper to align pages.  Andi Kleen hated it because
@@ -402,59 +402,45 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
        int ifd;
        struct stat st;
        unsigned long len;
-       void *iaddr;
 
        ifd = open_or_die(name, O_RDONLY);
        /* fstat() is needed to get the file size. */
        if (fstat(ifd, &st) < 0)
                err(1, "fstat() on initrd '%s'", name);
 
-       /* The length needs to be rounded up to a page size: mmap needs the
-        * address to be page aligned. */
+       /* We map the initrd at the top of memory, but mmap wants it to be
+        * page-aligned, so we round the size up for that. */
        len = page_align(st.st_size);
-       /* We map the initrd at the top of memory. */
-       iaddr = mmap((void *)mem - len, st.st_size,
-                    PROT_READ|PROT_EXEC|PROT_WRITE,
-                    MAP_FIXED|MAP_PRIVATE, ifd, 0);
-       if (iaddr != (void *)mem - len)
-               err(1, "Mmaping initrd '%s' returned %p not %p",
-                   name, iaddr, (void *)mem - len);
+       map_at(ifd, from_guest_phys(mem - len), 0, st.st_size);
        /* Once a file is mapped, you can close the file descriptor.  It's a
         * little odd, but quite useful. */
        close(ifd);
-       verbose("mapped initrd %s size=%lu @ %p\n", name, st.st_size, iaddr);
+       verbose("mapped initrd %s size=%lu @ %p\n", name, len, (void*)mem-len);
 
        /* We return the initrd size. */
        return len;
 }
 
-/* Once we know how much memory we have, and the address the Guest kernel
- * expects, we can construct simple linear page tables which will get the Guest
- * far enough into the boot to create its own.
+/* Once we know how much memory we have, we can construct simple linear page
+ * tables which set virtual == physical which will get the Guest far enough
+ * into the boot to create its own.
  *
  * We lay them out of the way, just below the initrd (which is why we need to
  * know its size). */
 static unsigned long setup_pagetables(unsigned long mem,
-                                     unsigned long initrd_size,
-                                     unsigned long page_offset)
+                                     unsigned long initrd_size)
 {
-       u32 *pgdir, *linear;
+       unsigned long *pgdir, *linear;
        unsigned int mapped_pages, i, linear_pages;
-       unsigned int ptes_per_page = getpagesize()/sizeof(u32);
+       unsigned int ptes_per_page = getpagesize()/sizeof(void *);
 
-       /* Ideally we map all physical memory starting at page_offset.
-        * However, if page_offset is 0xC0000000 we can only map 1G of physical
-        * (0xC0000000 + 1G overflows). */
-       if (mem <= -page_offset)
-               mapped_pages = mem/getpagesize();
-       else
-               mapped_pages = -page_offset/getpagesize();
+       mapped_pages = mem/getpagesize();
 
        /* Each PTE page can map ptes_per_page pages: how many do we need? */
        linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page;
 
        /* We put the toplevel page directory page at the top of memory. */
-       pgdir = (void *)mem - initrd_size - getpagesize();
+       pgdir = from_guest_phys(mem) - initrd_size - getpagesize();
 
        /* Now we use the next linear_pages pages as pte pages */
        linear = (void *)pgdir - linear_pages*getpagesize();
@@ -465,20 +451,19 @@ static unsigned long setup_pagetables(unsigned long mem,
        for (i = 0; i < mapped_pages; i++)
                linear[i] = ((i * getpagesize()) | PAGE_PRESENT);
 
-       /* The top level points to the linear page table pages above.  The
-        * entry representing page_offset points to the first one, and they
-        * continue from there. */
+       /* The top level points to the linear page table pages above. */
        for (i = 0; i < mapped_pages; i += ptes_per_page) {
-               pgdir[(i + page_offset/getpagesize())/ptes_per_page]
-                       = (((u32)linear + i*sizeof(u32)) | PAGE_PRESENT);
+               pgdir[i/ptes_per_page]
+                       = ((to_guest_phys(linear) + i*sizeof(void *))
+                          | PAGE_PRESENT);
        }
 
-       verbose("Linear mapping of %u pages in %u pte pages at %p\n",
-               mapped_pages, linear_pages, linear);
+       verbose("Linear mapping of %u pages in %u pte pages at %#lx\n",
+               mapped_pages, linear_pages, to_guest_phys(linear));
 
        /* We return the top level (guest-physical) address: the kernel needs
         * to know where it is. */
-       return (unsigned long)pgdir;
+       return to_guest_phys(pgdir);
 }
 
 /* Simple routine to roll all the commandline arguments together with spaces
@@ -498,14 +483,17 @@ static void concat(char *dst, char *args[])
 
 /* This is where we actually tell the kernel to initialize the Guest.  We saw
  * the arguments it expects when we looked at initialize() in lguest_user.c:
- * the top physical page to allow, the top level pagetable, the entry point and
- * the page_offset constant for the Guest. */
-static int tell_kernel(u32 pgdir, u32 start, u32 page_offset)
+ * the base of guest "physical" memory, the top physical page to allow, the
+ * top level pagetable and the entry point for the Guest. */
+static int tell_kernel(unsigned long pgdir, unsigned long start)
 {
-       u32 args[] = { LHREQ_INITIALIZE,
-                      top/getpagesize(), pgdir, start, page_offset };
+       unsigned long args[] = { LHREQ_INITIALIZE,
+                                (unsigned long)guest_base,
+                                guest_limit / getpagesize(), pgdir, start };
        int fd;
 
+       verbose("Guest: %p - %p (%#lx)\n",
+               guest_base, guest_base + guest_limit, guest_limit);
        fd = open_or_die("/dev/lguest", O_RDWR);
        if (write(fd, args, sizeof(args)) < 0)
                err(1, "Writing to /dev/lguest");
@@ -515,11 +503,11 @@ static int tell_kernel(u32 pgdir, u32 start, u32 page_offset)
 }
 /*:*/
 
-static void set_fd(int fd, struct device_list *devices)
+static void add_device_fd(int fd)
 {
-       FD_SET(fd, &devices->infds);
-       if (fd > devices->max_infd)
-               devices->max_infd = fd;
+       FD_SET(fd, &devices.infds);
+       if (fd > devices.max_infd)
+               devices.max_infd = fd;
 }
 
 /*L:200
@@ -537,36 +525,38 @@ static void set_fd(int fd, struct device_list *devices)
  *
  * This, of course, is merely a different *kind* of icky.
  */
-static void wake_parent(int pipefd, int lguest_fd, struct device_list *devices)
+static void wake_parent(int pipefd, int lguest_fd)
 {
        /* Add the pipe from the Launcher to the fdset in the device_list, so
         * we watch it, too. */
-       set_fd(pipefd, devices);
+       add_device_fd(pipefd);
 
        for (;;) {
-               fd_set rfds = devices->infds;
-               u32 args[] = { LHREQ_BREAK, 1 };
+               fd_set rfds = devices.infds;
+               unsigned long args[] = { LHREQ_BREAK, 1 };
 
                /* Wait until input is ready from one of the devices. */
-               select(devices->max_infd+1, &rfds, NULL, NULL, NULL);
+               select(devices.max_infd+1, &rfds, NULL, NULL, NULL);
                /* Is it a message from the Launcher? */
                if (FD_ISSET(pipefd, &rfds)) {
-                       int ignorefd;
+                       int fd;
                        /* If read() returns 0, it means the Launcher has
                         * exited.  We silently follow. */
-                       if (read(pipefd, &ignorefd, sizeof(ignorefd)) == 0)
+                       if (read(pipefd, &fd, sizeof(fd)) == 0)
                                exit(0);
-                       /* Otherwise it's telling us there's a problem with one
-                        * of the devices, and we should ignore that file
-                        * descriptor from now on. */
-                       FD_CLR(ignorefd, &devices->infds);
+                       /* Otherwise it's telling us to change what file
+                        * descriptors we're to listen to. */
+                       if (fd >= 0)
+                               FD_SET(fd, &devices.infds);
+                       else
+                               FD_CLR(-fd - 1, &devices.infds);
                } else /* Send LHREQ_BREAK command. */
                        write(lguest_fd, args, sizeof(args));
        }
 }
 
 /* This routine just sets up a pipe to the Waker process. */
-static int setup_waker(int lguest_fd, struct device_list *device_list)
+static int setup_waker(int lguest_fd)
 {
        int pipefd[2], child;
 
@@ -580,7 +570,7 @@ static int setup_waker(int lguest_fd, struct device_list *device_list)
        if (child == 0) {
                /* Close the "writing" end of our copy of the pipe */
                close(pipefd[1]);
-               wake_parent(pipefd[0], lguest_fd, device_list);
+               wake_parent(pipefd[0], lguest_fd);
        }
        /* Close the reading end of our copy of the pipe. */
        close(pipefd[0]);
@@ -602,83 +592,128 @@ static void *_check_pointer(unsigned long addr, unsigned int size,
 {
        /* We have to separately check addr and addr+size, because size could
         * be huge and addr + size might wrap around. */
-       if (addr >= top || addr + size >= top)
-               errx(1, "%s:%i: Invalid address %li", __FILE__, line, addr);
+       if (addr >= guest_limit || addr + size >= guest_limit)
+               errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr);
        /* We return a pointer for the caller's convenience, now we know it's
         * safe to use. */
-       return (void *)addr;
+       return from_guest_phys(addr);
 }
 /* A macro which transparently hands the line number to the real function. */
 #define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
 
-/* The Guest has given us the address of a "struct lguest_dma".  We check it's
- * OK and convert it to an iovec (which is a simple array of ptr/size
- * pairs). */
-static u32 *dma2iov(unsigned long dma, struct iovec iov[], unsigned *num)
+/* This function returns the next descriptor in the chain, or vq->vring.num. */
+static unsigned next_desc(struct virtqueue *vq, unsigned int i)
 {
-       unsigned int i;
-       struct lguest_dma *udma;
-
-       /* First we make sure that the array memory itself is valid. */
-       udma = check_pointer(dma, sizeof(*udma));
-       /* Now we check each element */
-       for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
-               /* A zero length ends the array. */
-               if (!udma->len[i])
-                       break;
+       unsigned int next;
 
-               iov[i].iov_base = check_pointer(udma->addr[i], udma->len[i]);
-               iov[i].iov_len = udma->len[i];
-       }
-       *num = i;
+       /* If this descriptor says it doesn't chain, we're done. */
+       if (!(vq->vring.desc[i].flags & VRING_DESC_F_NEXT))
+               return vq->vring.num;
+
+       /* Check they're not leading us off end of descriptors. */
+       next = vq->vring.desc[i].next;
+       /* Make sure compiler knows to grab that: we don't want it changing! */
+       wmb();
 
-       /* We return the pointer to where the caller should write the amount of
-        * the buffer used. */
-       return &udma->used_len;
+       if (next >= vq->vring.num)
+               errx(1, "Desc next is %u", next);
+
+       return next;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access.  Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->vring.num (which
+ * is never a valid descriptor number) if none was found. */
+static unsigned get_vq_desc(struct virtqueue *vq,
+                           struct iovec iov[],
+                           unsigned int *out_num, unsigned int *in_num)
+{
+       unsigned int i, head;
+
+       /* Check it isn't doing very strange things with descriptor numbers. */
+       if ((u16)(vq->vring.avail->idx - vq->last_avail_idx) > vq->vring.num)
+               errx(1, "Guest moved used index from %u to %u",
+                    vq->last_avail_idx, vq->vring.avail->idx);
+
+       /* If there's nothing new since last we looked, return invalid. */
+       if (vq->vring.avail->idx == vq->last_avail_idx)
+               return vq->vring.num;
+
+       /* Grab the next descriptor number they're advertising, and increment
+        * the index we've seen. */
+       head = vq->vring.avail->ring[vq->last_avail_idx++ % vq->vring.num];
+
+       /* If their number is silly, that's a fatal mistake. */
+       if (head >= vq->vring.num)
+               errx(1, "Guest says index %u is available", head);
+
+       /* When we start there are none of either input nor output. */
+       *out_num = *in_num = 0;
+
+       i = head;
+       do {
+               /* Grab the first descriptor, and check it's OK. */
+               iov[*out_num + *in_num].iov_len = vq->vring.desc[i].len;
+               iov[*out_num + *in_num].iov_base
+                       = check_pointer(vq->vring.desc[i].addr,
+                                       vq->vring.desc[i].len);
+               /* If this is an input descriptor, increment that count. */
+               if (vq->vring.desc[i].flags & VRING_DESC_F_WRITE)
+                       (*in_num)++;
+               else {
+                       /* If it's an output descriptor, they're all supposed
+                        * to come before any input descriptors. */
+                       if (*in_num)
+                               errx(1, "Descriptor has out after in");
+                       (*out_num)++;
+               }
+
+               /* If we've got too many, that implies a descriptor loop. */
+               if (*out_num + *in_num > vq->vring.num)
+                       errx(1, "Looped descriptor");
+       } while ((i = next_desc(vq, i)) != vq->vring.num);
+
+       return head;
 }
 
-/* This routine gets a DMA buffer from the Guest for a given key, and converts
- * it to an iovec array.  It returns the interrupt the Guest wants when we're
- * finished, and a pointer to the "used_len" field to fill in. */
-static u32 *get_dma_buffer(int fd, void *key,
-                          struct iovec iov[], unsigned int *num, u32 *irq)
+/* Once we've used one of their buffers, we tell them about it.  We'll then
+ * want to send them an interrupt, using trigger_irq(). */
+static void add_used(struct virtqueue *vq, unsigned int head, int len)
 {
-       u32 buf[] = { LHREQ_GETDMA, (u32)key };
-       unsigned long udma;
-       u32 *res;
-
-       /* Ask the kernel for a DMA buffer corresponding to this key. */
-       udma = write(fd, buf, sizeof(buf));
-       /* They haven't registered any, or they're all used? */
-       if (udma == (unsigned long)-1)
-               return NULL;
-
-       /* Convert it into our iovec array */
-       res = dma2iov(udma, iov, num);
-       /* The kernel stashes irq in ->used_len to get it out to us. */
-       *irq = *res;
-       /* Return a pointer to ((struct lguest_dma *)udma)->used_len. */
-       return res;
+       struct vring_used_elem *used;
+
+       /* Get a pointer to the next entry in the used ring. */
+       used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num];
+       used->id = head;
+       used->len = len;
+       /* Make sure buffer is written before we update index. */
+       wmb();
+       vq->vring.used->idx++;
 }
 
-/* This is a convenient routine to send the Guest an interrupt. */
-static void trigger_irq(int fd, u32 irq)
+/* This actually sends the interrupt for this virtqueue */
+static void trigger_irq(int fd, struct virtqueue *vq)
 {
-       u32 buf[] = { LHREQ_IRQ, irq };
+       unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
+
+       if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
+               return;
+
+       /* Send the Guest an interrupt tell them we used something up. */
        if (write(fd, buf, sizeof(buf)) != 0)
-               err(1, "Triggering irq %i", irq);
+               err(1, "Triggering irq %i", vq->config.irq);
 }
 
-/* This simply sets up an iovec array where we can put data to be discarded.
- * This happens when the Guest doesn't want or can't handle the input: we have
- * to get rid of it somewhere, and if we bury it in the ceiling space it will
- * start to smell after a week. */
-static void discard_iovec(struct iovec *iov, unsigned int *num)
+/* And here's the combo meal deal.  Supersize me! */
+static void add_used_and_trigger(int fd, struct virtqueue *vq,
+                                unsigned int head, int len)
 {
-       static char discard_buf[1024];
-       *num = 1;
-       iov->iov_base = discard_buf;
-       iov->iov_len = sizeof(discard_buf);
+       add_used(vq, head, len);
+       trigger_irq(fd, vq);
 }
 
 /* Here is the input terminal setting we save, and the routine to restore them
@@ -701,38 +736,39 @@ struct console_abort
 /* This is the routine which handles console input (ie. stdin). */
 static bool handle_console_input(int fd, struct device *dev)
 {
-       u32 irq = 0, *lenp;
        int len;
-       unsigned int num;
-       struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
+       unsigned int head, in_num, out_num;
+       struct iovec iov[dev->vq->vring.num];
        struct console_abort *abort = dev->priv;
 
-       /* First we get the console buffer from the Guest.  The key is dev->mem
-        * which was set to 0 in setup_console(). */
-       lenp = get_dma_buffer(fd, dev->mem, iov, &num, &irq);
-       if (!lenp) {
-               /* If it's not ready for input, warn and set up to discard. */
-               warn("console: no dma buffer!");
-               discard_iovec(iov, &num);
-       }
+       /* First we need a console buffer from the Guests's input virtqueue. */
+       head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
+
+       /* If they're not ready for input, stop listening to this file
+        * descriptor.  We'll start again once they add an input buffer. */
+       if (head == dev->vq->vring.num)
+               return false;
+
+       if (out_num)
+               errx(1, "Output buffers in console in queue?");
 
        /* This is why we convert to iovecs: the readv() call uses them, and so
         * it reads straight into the Guest's buffer. */
-       len = readv(dev->fd, iov, num);
+       len = readv(dev->fd, iov, in_num);
        if (len <= 0) {
                /* This implies that the console is closed, is /dev/null, or
-                * something went terribly wrong.  We still go through the rest
-                * of the logic, though, especially the exit handling below. */
+                * something went terribly wrong. */
                warnx("Failed to get console input, ignoring console.");
-               len = 0;
+               /* Put the input terminal back. */
+               restore_term();
+               /* Remove callback from input vq, so it doesn't restart us. */
+               dev->vq->handle_output = NULL;
+               /* Stop listening to this fd: don't call us again. */
+               return false;
        }
 
-       /* If we read the data into the Guest, fill in the length and send the
-        * interrupt. */
-       if (lenp) {
-               *lenp = len;
-               trigger_irq(fd, irq);
-       }
+       /* Tell the Guest about the new input. */
+       add_used_and_trigger(fd, dev->vq, head, len);
 
        /* Three ^C within one second?  Exit.
         *
@@ -746,7 +782,7 @@ static bool handle_console_input(int fd, struct device *dev)
                        struct timeval now;
                        gettimeofday(&now, NULL);
                        if (now.tv_sec <= abort->start.tv_sec+1) {
-                               u32 args[] = { LHREQ_BREAK, 0 };
+                               unsigned long args[] = { LHREQ_BREAK, 0 };
                                /* Close the fd so Waker will know it has to
                                 * exit. */
                                close(waker_fd);
@@ -761,214 +797,163 @@ static bool handle_console_input(int fd, struct device *dev)
                /* Any other key resets the abort counter. */
                abort->count = 0;
 
-       /* Now, if we didn't read anything, put the input terminal back and
-        * return failure (meaning, don't call us again). */
-       if (!len) {
-               restore_term();
-               return false;
-       }
        /* Everything went OK! */
        return true;
 }
 
-/* Handling console output is much simpler than input. */
-static u32 handle_console_output(int fd, const struct iovec *iov,
-                                unsigned num, struct device*dev)
+/* Handling output for console is simple: we just get all the output buffers
+ * and write them to stdout. */
+static void handle_console_output(int fd, struct virtqueue *vq)
 {
-       /* Whatever the Guest sends, write it to standard output.  Return the
-        * number of bytes written. */
-       return writev(STDOUT_FILENO, iov, num);
-}
-
-/* Guest->Host network output is also pretty easy. */
-static u32 handle_tun_output(int fd, const struct iovec *iov,
-                            unsigned num, struct device *dev)
-{
-       /* We put a flag in the "priv" pointer of the network device, and set
-        * it as soon as we see output.  We'll see why in handle_tun_input() */
-       *(bool *)dev->priv = true;
-       /* Whatever packet the Guest sent us, write it out to the tun
-        * device. */
-       return writev(dev->fd, iov, num);
+       unsigned int head, out, in;
+       int len;
+       struct iovec iov[vq->vring.num];
+
+       /* Keep getting output buffers from the Guest until we run out. */
+       while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
+               if (in)
+                       errx(1, "Input buffers in output queue?");
+               len = writev(STDOUT_FILENO, iov, out);
+               add_used_and_trigger(fd, vq, head, len);
+       }
 }
 
-/* This matches the peer_key() in lguest_net.c.  The key for any given slot
- * is the address of the network device's page plus 4 * the slot number. */
-static unsigned long peer_offset(unsigned int peernum)
+/* Handling output for network is also simple: we get all the output buffers
+ * and write them (ignoring the first element) to this device's file descriptor
+ * (stdout). */
+static void handle_net_output(int fd, struct virtqueue *vq)
 {
-       return 4 * peernum;
+       unsigned int head, out, in;
+       int len;
+       struct iovec iov[vq->vring.num];
+
+       /* Keep getting output buffers from the Guest until we run out. */
+       while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
+               if (in)
+                       errx(1, "Input buffers in output queue?");
+               /* Check header, but otherwise ignore it (we said we supported
+                * no features). */
+               (void)convert(&iov[0], struct virtio_net_hdr);
+               len = writev(vq->dev->fd, iov+1, out-1);
+               add_used_and_trigger(fd, vq, head, len);
+       }
 }
 
-/* This is where we handle a packet coming in from the tun device */
+/* This is where we handle a packet coming in from the tun device to our
+ * Guest. */
 static bool handle_tun_input(int fd, struct device *dev)
 {
-       u32 irq = 0, *lenp;
+       unsigned int head, in_num, out_num;
        int len;
-       unsigned num;
-       struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
+       struct iovec iov[dev->vq->vring.num];
+       struct virtio_net_hdr *hdr;
 
-       /* First we get a buffer the Guest has bound to its key. */
-       lenp = get_dma_buffer(fd, dev->mem+peer_offset(NET_PEERNUM), iov, &num,
-                             &irq);
-       if (!lenp) {
+       /* First we need a network buffer from the Guests's recv virtqueue. */
+       head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
+       if (head == dev->vq->vring.num) {
                /* Now, it's expected that if we try to send a packet too
-                * early, the Guest won't be ready yet.  This is why we set a
-                * flag when the Guest sends its first packet.  If it's sent a
-                * packet we assume it should be ready to receive them.
-                *
-                * Actually, this is what the status bits in the descriptor are
-                * for: we should *use* them.  FIXME! */
-               if (*(bool *)dev->priv)
+                * early, the Guest won't be ready yet.  Wait until the device
+                * status says it's ready. */
+               /* FIXME: Actually want DRIVER_ACTIVE here. */
+               if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK)
                        warn("network: no dma buffer!");
-               discard_iovec(iov, &num);
-       }
+               /* We'll turn this back on if input buffers are registered. */
+               return false;
+       } else if (out_num)
+               errx(1, "Output buffers in network recv queue?");
+
+       /* First element is the header: we set it to 0 (no features). */
+       hdr = convert(&iov[0], struct virtio_net_hdr);
+       hdr->flags = 0;
+       hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
 
        /* Read the packet from the device directly into the Guest's buffer. */
-       len = readv(dev->fd, iov, num);
+       len = readv(dev->fd, iov+1, in_num-1);
        if (len <= 0)
                err(1, "reading network");
 
-       /* Write the used_len, and trigger the interrupt for the Guest */
-       if (lenp) {
-               *lenp = len;
-               trigger_irq(fd, irq);
-       }
+       /* Tell the Guest about the new packet. */
+       add_used_and_trigger(fd, dev->vq, head, sizeof(*hdr) + len);
+
        verbose("tun input packet len %i [%02x %02x] (%s)\n", len,
-               ((u8 *)iov[0].iov_base)[0], ((u8 *)iov[0].iov_base)[1],
-               lenp ? "sent" : "discarded");
+               ((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1],
+               head != dev->vq->vring.num ? "sent" : "discarded");
+
        /* All good. */
        return true;
 }
 
-/* The last device handling routine is block output: the Guest has sent a DMA
- * to the block device.  It will have placed the command it wants in the
- * "struct lguest_block_page". */
-static u32 handle_block_output(int fd, const struct iovec *iov,
-                              unsigned num, struct device *dev)
+/* This callback ensures we try again, in case we stopped console or net
+ * delivery because Guest didn't have any buffers. */
+static void enable_fd(int fd, struct virtqueue *vq)
 {
-       struct lguest_block_page *p = dev->mem;
-       u32 irq, *lenp;
-       unsigned int len, reply_num;
-       struct iovec reply[LGUEST_MAX_DMA_SECTIONS];
-       off64_t device_len, off = (off64_t)p->sector * 512;
-
-       /* First we extract the device length from the dev->priv pointer. */
-       device_len = *(off64_t *)dev->priv;
-
-       /* We first check that the read or write is within the length of the
-        * block file. */
-       if (off >= device_len)
-               err(1, "Bad offset %llu vs %llu", off, device_len);
-       /* Move to the right location in the block file.  This shouldn't fail,
-        * but best to check. */
-       if (lseek64(dev->fd, off, SEEK_SET) != off)
-               err(1, "Bad seek to sector %i", p->sector);
-
-       verbose("Block: %s at offset %llu\n", p->type ? "WRITE" : "READ", off);
-
-       /* They were supposed to bind a reply buffer at key equal to the start
-        * of the block device memory.  We need this to tell them when the
-        * request is finished. */
-       lenp = get_dma_buffer(fd, dev->mem, reply, &reply_num, &irq);
-       if (!lenp)
-               err(1, "Block request didn't give us a dma buffer");
-
-       if (p->type) {
-               /* A write request.  The DMA they sent contained the data, so
-                * write it out. */
-               len = writev(dev->fd, iov, num);
-               /* Grr... Now we know how long the "struct lguest_dma" they
-                * sent was, we make sure they didn't try to write over the end
-                * of the block file (possibly extending it). */
-               if (off + len > device_len) {
-                       /* Trim it back to the correct length */
-                       ftruncate64(dev->fd, device_len);
-                       /* Die, bad Guest, die. */
-                       errx(1, "Write past end %llu+%u", off, len);
-               }
-               /* The reply length is 0: we just send back an empty DMA to
-                * interrupt them and tell them the write is finished. */
-               *lenp = 0;
-       } else {
-               /* A read request.  They sent an empty DMA to start the
-                * request, and we put the read contents into the reply
-                * buffer. */
-               len = readv(dev->fd, reply, reply_num);
-               *lenp = len;
-       }
-
-       /* The result is 1 (done), 2 if there was an error (short read or
-        * write). */
-       p->result = 1 + (p->bytes != len);
-       /* Now tell them we've used their reply buffer. */
-       trigger_irq(fd, irq);
-
-       /* We're supposed to return the number of bytes of the output buffer we
-        * used.  But the block device uses the "result" field instead, so we
-        * don't bother. */
-       return 0;
+       add_device_fd(vq->dev->fd);
+       /* Tell waker to listen to it again */
+       write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
 }
 
-/* This is the generic routine we call when the Guest sends some DMA out. */
-static void handle_output(int fd, unsigned long dma, unsigned long key,
-                         struct device_list *devices)
+/* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */
+static void handle_output(int fd, unsigned long addr)
 {
        struct device *i;
-       u32 *lenp;
-       struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
-       unsigned num = 0;
-
-       /* Convert the "struct lguest_dma" they're sending to a "struct
-        * iovec". */
-       lenp = dma2iov(dma, iov, &num);
-
-       /* Check each device: if they expect output to this key, tell them to
-        * handle it. */
-       for (i = devices->dev; i; i = i->next) {
-               if (i->handle_output && key == i->watch_key) {
-                       /* We write the result straight into the used_len field
-                        * for them. */
-                       *lenp = i->handle_output(fd, iov, num, i);
-                       return;
+       struct virtqueue *vq;
+
+       /* Check each virtqueue. */
+       for (i = devices.dev; i; i = i->next) {
+               for (vq = i->vq; vq; vq = vq->next) {
+                       if (vq->config.pfn == addr/getpagesize()
+                           && vq->handle_output) {
+                               verbose("Output to %s\n", vq->dev->name);
+                               vq->handle_output(fd, vq);
+                               return;
+                       }
                }
        }
 
-       /* This can happen: the kernel sends any SEND_DMA which doesn't match
-        * another Guest to us.  It could be that another Guest just left a
-        * network, for example.  But it's unusual. */
-       warnx("Pending dma %p, key %p", (void *)dma, (void *)key);
+       /* Early console write is done using notify on a nul-terminated string
+        * in Guest memory. */
+       if (addr >= guest_limit)
+               errx(1, "Bad NOTIFY %#lx", addr);
+
+       write(STDOUT_FILENO, from_guest_phys(addr),
+             strnlen(from_guest_phys(addr), guest_limit - addr));
 }
 
 /* This is called when the waker wakes us up: check for incoming file
  * descriptors. */
-static void handle_input(int fd, struct device_list *devices)
+static void handle_input(int fd)
 {
        /* select() wants a zeroed timeval to mean "don't wait". */
        struct timeval poll = { .tv_sec = 0, .tv_usec = 0 };
 
        for (;;) {
                struct device *i;
-               fd_set fds = devices->infds;
+               fd_set fds = devices.infds;
 
                /* If nothing is ready, we're done. */
-               if (select(devices->max_infd+1, &fds, NULL, NULL, &poll) == 0)
+               if (select(devices.max_infd+1, &fds, NULL, NULL, &poll) == 0)
                        break;
 
                /* Otherwise, call the device(s) which have readable
                 * file descriptors and a method of handling them.  */
-               for (i = devices->dev; i; i = i->next) {
+               for (i = devices.dev; i; i = i->next) {
                        if (i->handle_input && FD_ISSET(i->fd, &fds)) {
+                               int dev_fd;
+                               if (i->handle_input(fd, i))
+                                       continue;
+
                                /* If handle_input() returns false, it means we
-                                * should no longer service it.
-                                * handle_console_input() does this. */
-                               if (!i->handle_input(fd, i)) {
-                                       /* Clear it from the set of input file
-                                        * descriptors kept at the head of the
-                                        * device list. */
-                                       FD_CLR(i->fd, &devices->infds);
-                                       /* Tell waker to ignore it too... */
-                                       write(waker_fd, &i->fd, sizeof(i->fd));
-                               }
+                                * should no longer service it.  Networking and
+                                * console do this when there's no input
+                                * buffers to deliver into.  Console also uses
+                                * it when it discovers that stdin is
+                                * closed. */
+                               FD_CLR(i->fd, &devices.infds);
+                               /* Tell waker to ignore it too, by sending a
+                                * negative fd number (-1, since 0 is a valid
+                                * FD number). */
+                               dev_fd = -i->fd - 1;
+                               write(waker_fd, &dev_fd, sizeof(dev_fd));
                        }
                }
        }
@@ -982,43 +967,93 @@ static void handle_input(int fd, struct device_list *devices)
  * routines to allocate them.
  *
  * This routine allocates a new "struct lguest_device_desc" from descriptor
- * table in the devices array just above the Guest's normal memory. */
-static struct lguest_device_desc *
-new_dev_desc(struct lguest_device_desc *descs,
-            u16 type, u16 features, u16 num_pages)
+ * table just above the Guest's normal memory.  It returns a pointer to that
+ * descriptor. */
+static struct lguest_device_desc *new_dev_desc(u16 type)
 {
-       unsigned int i;
+       struct lguest_device_desc *d;
 
-       for (i = 0; i < LGUEST_MAX_DEVICES; i++) {
-               if (!descs[i].type) {
-                       descs[i].type = type;
-                       descs[i].features = features;
-                       descs[i].num_pages = num_pages;
-                       /* If they said the device needs memory, we allocate
-                        * that now, bumping up the top of Guest memory. */
-                       if (num_pages) {
-                               map_zeroed_pages(top, num_pages);
-                               descs[i].pfn = top/getpagesize();
-                               top += num_pages*getpagesize();
-                       }
-                       return &descs[i];
-               }
-       }
-       errx(1, "too many devices");
+       /* We only have one page for all the descriptors. */
+       if (devices.desc_used + sizeof(*d) > getpagesize())
+               errx(1, "Too many devices");
+
+       /* We don't need to set config_len or status: page is 0 already. */
+       d = (void *)devices.descpage + devices.desc_used;
+       d->type = type;
+       devices.desc_used += sizeof(*d);
+
+       return d;
 }
 
-/* This monster routine does all the creation and setup of a new device,
- * including caling new_dev_desc() to allocate the descriptor and device
- * memory. */
-static struct device *new_device(struct device_list *devices,
-                                u16 type, u16 num_pages, u16 features,
-                                int fd,
-                                bool (*handle_input)(int, struct device *),
-                                unsigned long watch_off,
-                                u32 (*handle_output)(int,
-                                                     const struct iovec *,
-                                                     unsigned,
-                                                     struct device *))
+/* Each device descriptor is followed by some configuration information.
+ * The first byte is a "status" byte for the Guest to report what's happening.
+ * After that are fields: u8 type, u8 len, [... len bytes...].
+ *
+ * This routine adds a new field to an existing device's descriptor.  It only
+ * works for the last device, but that's OK because that's how we use it. */
+static void add_desc_field(struct device *dev, u8 type, u8 len, const void *c)
+{
+       /* This is the last descriptor, right? */
+       assert(devices.descpage + devices.desc_used
+              == (u8 *)(dev->desc + 1) + dev->desc->config_len);
+
+       /* We only have one page of device descriptions. */
+       if (devices.desc_used + 2 + len > getpagesize())
+               errx(1, "Too many devices");
+
+       /* Copy in the new config header: type then length. */
+       devices.descpage[devices.desc_used++] = type;
+       devices.descpage[devices.desc_used++] = len;
+       memcpy(devices.descpage + devices.desc_used, c, len);
+       devices.desc_used += len;
+
+       /* Update the device descriptor length: two byte head then data. */
+       dev->desc->config_len += 2 + len;
+}
+
+/* This routine adds a virtqueue to a device.  We specify how many descriptors
+ * the virtqueue is to have. */
+static void add_virtqueue(struct device *dev, unsigned int num_descs,
+                         void (*handle_output)(int fd, struct virtqueue *me))
+{
+       unsigned int pages;
+       struct virtqueue **i, *vq = malloc(sizeof(*vq));
+       void *p;
+
+       /* First we need some pages for this virtqueue. */
+       pages = (vring_size(num_descs) + getpagesize() - 1) / getpagesize();
+       p = get_pages(pages);
+
+       /* Initialize the configuration. */
+       vq->config.num = num_descs;
+       vq->config.irq = devices.next_irq++;
+       vq->config.pfn = to_guest_phys(p) / getpagesize();
+
+       /* Initialize the vring. */
+       vring_init(&vq->vring, num_descs, p);
+
+       /* Add the configuration information to this device's descriptor. */
+       add_desc_field(dev, VIRTIO_CONFIG_F_VIRTQUEUE,
+                      sizeof(vq->config), &vq->config);
+
+       /* Add to tail of list, so dev->vq is first vq, dev->vq->next is
+        * second.  */
+       for (i = &dev->vq; *i; i = &(*i)->next);
+       *i = vq;
+
+       /* Link virtqueue back to device. */
+       vq->dev = dev;
+
+       /* Set up handler. */
+       vq->handle_output = handle_output;
+       if (!handle_output)
+               vq->vring.used->flags = VRING_USED_F_NO_NOTIFY;
+}
+
+/* This routine does all the creation and setup of a new device, including
+ * caling new_dev_desc() to allocate the descriptor and device memory. */
+static struct device *new_device(const char *name, u16 type, int fd,
+                                bool (*handle_input)(int, struct device *))
 {
        struct device *dev = malloc(sizeof(*dev));
 
@@ -1026,27 +1061,25 @@ static struct device *new_device(struct device_list *devices,
         * easier, but the user expects the devices to be arranged on the bus
         * in command-line order.  The first network device on the command line
         * is eth0, the first block device /dev/lgba, etc. */
-       *devices->lastdev = dev;
+       *devices.lastdev = dev;
        dev->next = NULL;
-       devices->lastdev = &dev->next;
+       devices.lastdev = &dev->next;
 
        /* Now we populate the fields one at a time. */
        dev->fd = fd;
        /* If we have an input handler for this file descriptor, then we add it
         * to the device_list's fdset and maxfd. */
        if (handle_input)
-               set_fd(dev->fd, devices);
-       dev->desc = new_dev_desc(devices->descs, type, features, num_pages);
-       dev->mem = (void *)(dev->desc->pfn * getpagesize());
+               add_device_fd(dev->fd);
+       dev->desc = new_dev_desc(type);
        dev->handle_input = handle_input;
-       dev->watch_key = (unsigned long)dev->mem + watch_off;
-       dev->handle_output = handle_output;
+       dev->name = name;
        return dev;
 }
 
 /* Our first setup routine is the console.  It's a fairly simple device, but
  * UNIX tty handling makes it uglier than it could be. */
-static void setup_console(struct device_list *devices)
+static void setup_console(void)
 {
        struct device *dev;
 
@@ -1062,127 +1095,38 @@ static void setup_console(struct device_list *devices)
                atexit(restore_term);
        }
 
-       /* We don't currently require any memory for the console, so we ask for
-        * 0 pages. */
-       dev = new_device(devices, LGUEST_DEVICE_T_CONSOLE, 0, 0,
-                        STDIN_FILENO, handle_console_input,
-                        LGUEST_CONSOLE_DMA_KEY, handle_console_output);
+       dev = new_device("console", VIRTIO_ID_CONSOLE,
+                        STDIN_FILENO, handle_console_input);
        /* We store the console state in dev->priv, and initialize it. */
        dev->priv = malloc(sizeof(struct console_abort));
        ((struct console_abort *)dev->priv)->count = 0;
-       verbose("device %p: console\n",
-               (void *)(dev->desc->pfn * getpagesize()));
-}
 
-/* Setting up a block file is also fairly straightforward. */
-static void setup_block_file(const char *filename, struct device_list *devices)
-{
-       int fd;
-       struct device *dev;
-       off64_t *device_len;
-       struct lguest_block_page *p;
-
-       /* We open with O_LARGEFILE because otherwise we get stuck at 2G.  We
-        * open with O_DIRECT because otherwise our benchmarks go much too
-        * fast. */
-       fd = open_or_die(filename, O_RDWR|O_LARGEFILE|O_DIRECT);
-
-       /* We want one page, and have no input handler (the block file never
-        * has anything interesting to say to us).  Our timing will be quite
-        * random, so it should be a reasonable randomness source. */
-       dev = new_device(devices, LGUEST_DEVICE_T_BLOCK, 1,
-                        LGUEST_DEVICE_F_RANDOMNESS,
-                        fd, NULL, 0, handle_block_output);
-
-       /* We store the device size in the private area */
-       device_len = dev->priv = malloc(sizeof(*device_len));
-       /* This is the safe way of establishing the size of our device: it
-        * might be a normal file or an actual block device like /dev/hdb. */
-       *device_len = lseek64(fd, 0, SEEK_END);
-
-       /* The device memory is a "struct lguest_block_page".  It's zeroed
-        * already, we just need to put in the device size.  Block devices
-        * think in sectors (ie. 512 byte chunks), so we translate here. */
-       p = dev->mem;
-       p->num_sectors = *device_len/512;
-       verbose("device %p: block %i sectors\n",
-               (void *)(dev->desc->pfn * getpagesize()), p->num_sectors);
+       /* The console needs two virtqueues: the input then the output.  When
+        * they put something the input queue, we make sure we're listening to
+        * stdin.  When they put something in the output queue, we write it to
+        * stdout.  */
+       add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
+       add_virtqueue(dev, VIRTQUEUE_NUM, handle_console_output);
+
+       verbose("device %u: console\n", devices.device_num++);
 }
+/*:*/
 
-/*
- * Network Devices.
+/*M:010 Inter-guest networking is an interesting area.  Simplest is to have a
+ * --sharenet=<name> option which opens or creates a named pipe.  This can be
+ * used to send packets to another guest in a 1:1 manner.
  *
- * Setting up network devices is quite a pain, because we have three types.
- * First, we have the inter-Guest network.  This is a file which is mapped into
- * the address space of the Guests who are on the network.  Because it is a
- * shared mapping, the same page underlies all the devices, and they can send
- * DMA to each other.
+ * More sopisticated is to use one of the tools developed for project like UML
+ * to do networking.
  *
- * Remember from our network driver, the Guest is told what slot in the page it
- * is to use.  We use exclusive fnctl locks to reserve a slot.  If another
- * Guest is using a slot, the lock will fail and we try another.  Because fnctl
- * locks are cleaned up automatically when we die, this cleverly means that our
- * reservation on the slot will vanish if we crash. */
-static unsigned int find_slot(int netfd, const char *filename)
-{
-       struct flock fl;
-
-       fl.l_type = F_WRLCK;
-       fl.l_whence = SEEK_SET;
-       fl.l_len = 1;
-       /* Try a 1 byte lock in each possible position number */
-       for (fl.l_start = 0;
-            fl.l_start < getpagesize()/sizeof(struct lguest_net);
-            fl.l_start++) {
-               /* If we succeed, return the slot number. */
-               if (fcntl(netfd, F_SETLK, &fl) == 0)
-                       return fl.l_start;
-       }
-       errx(1, "No free slots in network file %s", filename);
-}
-
-/* This function sets up the network file */
-static void setup_net_file(const char *filename,
-                          struct device_list *devices)
-{
-       int netfd;
-       struct device *dev;
-
-       /* We don't use open_or_die() here: for friendliness we create the file
-        * if it doesn't already exist. */
-       netfd = open(filename, O_RDWR, 0);
-       if (netfd < 0) {
-               if (errno == ENOENT) {
-                       netfd = open(filename, O_RDWR|O_CREAT, 0600);
-                       if (netfd >= 0) {
-                               /* If we succeeded, initialize the file with a
-                                * blank page. */
-                               char page[getpagesize()];
-                               memset(page, 0, sizeof(page));
-                               write(netfd, page, sizeof(page));
-                       }
-               }
-               if (netfd < 0)
-                       err(1, "cannot open net file '%s'", filename);
-       }
-
-       /* We need 1 page, and the features indicate the slot to use and that
-        * no checksum is needed.  We never touch this device again; it's
-        * between the Guests on the network, so we don't register input or
-        * output handlers. */
-       dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
-                        find_slot(netfd, filename)|LGUEST_NET_F_NOCSUM,
-                        -1, NULL, 0, NULL);
-
-       /* Map the shared file. */
-       if (mmap(dev->mem, getpagesize(), PROT_READ|PROT_WRITE,
-                        MAP_FIXED|MAP_SHARED, netfd, 0) != dev->mem)
-                       err(1, "could not mmap '%s'", filename);
-       verbose("device %p: shared net %s, peer %i\n",
-               (void *)(dev->desc->pfn * getpagesize()), filename,
-               dev->desc->features & ~LGUEST_NET_F_NOCSUM);
-}
-/*:*/
+ * Faster is to do virtio bonding in kernel.  Doing this 1:1 would be
+ * completely generic ("here's my vring, attach to your vring") and would work
+ * for any traffic.  Of course, namespace and permissions issues need to be
+ * dealt with.  A more sophisticated "multi-channel" virtio_net.c could hide
+ * multiple inter-guest channels behind one interface, although it would
+ * require some manner of hotplugging new virtio channels.
+ *
+ * Finally, we could implement a virtio network switch in the kernel. :*/
 
 static u32 str2ip(const char *ipaddr)
 {
@@ -1217,7 +1161,7 @@ static void add_to_bridge(int fd, const char *if_name, const char *br_name)
 
 /* This sets up the Host end of the network device with an IP address, brings
  * it up so packets will flow, the copies the MAC address into the hwaddr
- * pointer (in practice, the Host's slot in the network device's memory). */
+ * pointer. */
 static void configure_device(int fd, const char *devname, u32 ipaddr,
                             unsigned char hwaddr[6])
 {
@@ -1243,18 +1187,18 @@ static void configure_device(int fd, const char *devname, u32 ipaddr,
        memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);
 }
 
-/*L:195 The other kind of network is a Host<->Guest network.  This can either
- * use briding or routing, but the principle is the same: it uses the "tun"
- * device to inject packets into the Host as if they came in from a normal
- * network card.  We just shunt packets between the Guest and the tun
- * device. */
-static void setup_tun_net(const char *arg, struct device_list *devices)
+/*L:195 Our network is a Host<->Guest network.  This can either use bridging or
+ * routing, but the principle is the same: it uses the "tun" device to inject
+ * packets into the Host as if they came in from a normal network card.  We
+ * just shunt packets between the Guest and the tun device. */
+static void setup_tun_net(const char *arg)
 {
        struct device *dev;
        struct ifreq ifr;
        int netfd, ipfd;
        u32 ip;
        const char *br_name = NULL;
+       u8 hwaddr[6];
 
        /* We open the /dev/net/tun device and tell it we want a tap device.  A
         * tap device is like a tun device, only somehow different.  To tell
@@ -1270,21 +1214,13 @@ static void setup_tun_net(const char *arg, struct device_list *devices)
         * device: trust us! */
        ioctl(netfd, TUNSETNOCSUM, 1);
 
-       /* We create the net device with 1 page, using the features field of
-        * the descriptor to tell the Guest it is in slot 1 (NET_PEERNUM), and
-        * that the device has fairly random timing.  We do *not* specify
-        * LGUEST_NET_F_NOCSUM: these packets can reach the real world.
-        *
-        * We will put our MAC address is slot 0 for the Guest to see, so
-        * it will send packets to us using the key "peer_offset(0)": */
-       dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
-                        NET_PEERNUM|LGUEST_DEVICE_F_RANDOMNESS, netfd,
-                        handle_tun_input, peer_offset(0), handle_tun_output);
+       /* First we create a new network device. */
+       dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input);
 
-       /* We keep a flag which says whether we've seen packets come out from
-        * this network device. */
-       dev->priv = malloc(sizeof(bool));
-       *(bool *)dev->priv = false;
+       /* Network devices need a receive and a send queue, just like
+        * console. */
+       add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
+       add_virtqueue(dev, VIRTQUEUE_NUM, handle_net_output);
 
        /* We need a socket to perform the magic network ioctls to bring up the
         * tap interface, connect to the bridge etc.  Any socket will do! */
@@ -1300,44 +1236,251 @@ static void setup_tun_net(const char *arg, struct device_list *devices)
        } else /* It is an IP address to set up the device with */
                ip = str2ip(arg);
 
-       /* We are peer 0, ie. first slot, so we hand dev->mem to this routine
-        * to write the MAC address at the start of the device memory.  */
-       configure_device(ipfd, ifr.ifr_name, ip, dev->mem);
+       /* Set up the tun device, and get the mac address for the interface. */
+       configure_device(ipfd, ifr.ifr_name, ip, hwaddr);
 
-       /* Set "promisc" bit: we want every single packet if we're going to
-        * bridge to other machines (and otherwise it doesn't matter). */
-       *((u8 *)dev->mem) |= 0x1;
+       /* Tell Guest what MAC address to use. */
+       add_desc_field(dev, VIRTIO_CONFIG_NET_MAC_F, sizeof(hwaddr), hwaddr);
 
+       /* We don't seed the socket any more; setup is done. */
        close(ipfd);
 
-       verbose("device %p: tun net %u.%u.%u.%u\n",
-               (void *)(dev->desc->pfn * getpagesize()),
-               (u8)(ip>>24), (u8)(ip>>16), (u8)(ip>>8), (u8)ip);
+       verbose("device %u: tun net %u.%u.%u.%u\n",
+               devices.device_num++,
+               (u8)(ip>>24),(u8)(ip>>16),(u8)(ip>>8),(u8)ip);
        if (br_name)
                verbose("attached to bridge: %s\n", br_name);
 }
+
+
+/*
+ * Block device.
+ *
+ * Serving a block device is really easy: the Guest asks for a block number and
+ * we read or write that position in the file.
+ *
+ * Unfortunately, this is amazingly slow: the Guest waits until the read is
+ * finished before running anything else, even if it could be doing useful
+ * work.  We could use async I/O, except it's reputed to suck so hard that
+ * characters actually go missing from your code when you try to use it.
+ *
+ * So we farm the I/O out to thread, and communicate with it via a pipe. */
+
+/* This hangs off device->priv, with the data. */
+struct vblk_info
+{
+       /* The size of the file. */
+       off64_t len;
+
+       /* The file descriptor for the file. */
+       int fd;
+
+       /* IO thread listens on this file descriptor [0]. */
+       int workpipe[2];
+
+       /* IO thread writes to this file descriptor to mark it done, then
+        * Launcher triggers interrupt to Guest. */
+       int done_fd;
+};
+
+/* This is the core of the I/O thread.  It returns true if it did something. */
+static bool service_io(struct device *dev)
+{
+       struct vblk_info *vblk = dev->priv;
+       unsigned int head, out_num, in_num, wlen;
+       int ret;
+       struct virtio_blk_inhdr *in;
+       struct virtio_blk_outhdr *out;
+       struct iovec iov[dev->vq->vring.num];
+       off64_t off;
+
+       head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
+       if (head == dev->vq->vring.num)
+               return false;
+
+       if (out_num == 0 || in_num == 0)
+               errx(1, "Bad virtblk cmd %u out=%u in=%u",
+                    head, out_num, in_num);
+
+       out = convert(&iov[0], struct virtio_blk_outhdr);
+       in = convert(&iov[out_num+in_num-1], struct virtio_blk_inhdr);
+       off = out->sector * 512;
+
+       /* This is how we implement barriers.  Pretty poor, no? */
+       if (out->type & VIRTIO_BLK_T_BARRIER)
+               fdatasync(vblk->fd);
+
+       if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
+               fprintf(stderr, "Scsi commands unsupported\n");
+               in->status = VIRTIO_BLK_S_UNSUPP;
+               wlen = sizeof(in);
+       } else if (out->type & VIRTIO_BLK_T_OUT) {
+               /* Write */
+
+               /* Move to the right location in the block file.  This can fail
+                * if they try to write past end. */
+               if (lseek64(vblk->fd, off, SEEK_SET) != off)
+                       err(1, "Bad seek to sector %llu", out->sector);
+
+               ret = writev(vblk->fd, iov+1, out_num-1);
+               verbose("WRITE to sector %llu: %i\n", out->sector, ret);
+
+               /* Grr... Now we know how long the descriptor they sent was, we
+                * make sure they didn't try to write over the end of the block
+                * file (possibly extending it). */
+               if (ret > 0 && off + ret > vblk->len) {
+                       /* Trim it back to the correct length */
+                       ftruncate64(vblk->fd, vblk->len);
+                       /* Die, bad Guest, die. */
+                       errx(1, "Write past end %llu+%u", off, ret);
+               }
+               wlen = sizeof(in);
+               in->status = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
+       } else {
+               /* Read */
+
+               /* Move to the right location in the block file.  This can fail
+                * if they try to read past end. */
+               if (lseek64(vblk->fd, off, SEEK_SET) != off)
+                       err(1, "Bad seek to sector %llu", out->sector);
+
+               ret = readv(vblk->fd, iov+1, in_num-1);
+               verbose("READ from sector %llu: %i\n", out->sector, ret);
+               if (ret >= 0) {
+                       wlen = sizeof(in) + ret;
+                       in->status = VIRTIO_BLK_S_OK;
+               } else {
+                       wlen = sizeof(in);
+                       in->status = VIRTIO_BLK_S_IOERR;
+               }
+       }
+
+       /* We can't trigger an IRQ, because we're not the Launcher.  It does
+        * that when we tell it we're done. */
+       add_used(dev->vq, head, wlen);
+       return true;
+}
+
+/* This is the thread which actually services the I/O. */
+static int io_thread(void *_dev)
+{
+       struct device *dev = _dev;
+       struct vblk_info *vblk = dev->priv;
+       char c;
+
+       /* Close other side of workpipe so we get 0 read when main dies. */
+       close(vblk->workpipe[1]);
+       /* Close the other side of the done_fd pipe. */
+       close(dev->fd);
+
+       /* When this read fails, it means Launcher died, so we follow. */
+       while (read(vblk->workpipe[0], &c, 1) == 1) {
+               /* We acknowledge each request immediately, to reduce latency,
+                * rather than waiting until we've done them all.  I haven't
+                * measured to see if it makes any difference. */
+               while (service_io(dev))
+                       write(vblk->done_fd, &c, 1);
+       }
+       return 0;
+}
+
+/* When the thread says some I/O is done, we interrupt the Guest. */
+static bool handle_io_finish(int fd, struct device *dev)
+{
+       char c;
+
+       /* If child died, presumably it printed message. */
+       if (read(dev->fd, &c, 1) != 1)
+               exit(1);
+
+       /* It did some work, so trigger the irq. */
+       trigger_irq(fd, dev->vq);
+       return true;
+}
+
+/* When the Guest submits some I/O, we wake the I/O thread. */
+static void handle_virtblk_output(int fd, struct virtqueue *vq)
+{
+       struct vblk_info *vblk = vq->dev->priv;
+       char c = 0;
+
+       /* Wake up I/O thread and tell it to go to work! */
+       if (write(vblk->workpipe[1], &c, 1) != 1)
+               /* Presumably it indicated why it died. */
+               exit(1);
+}
+
+/* This creates a virtual block device. */
+static void setup_block_file(const char *filename)
+{
+       int p[2];
+       struct device *dev;
+       struct vblk_info *vblk;
+       void *stack;
+       u64 cap;
+       unsigned int val;
+
+       /* This is the pipe the I/O thread will use to tell us I/O is done. */
+       pipe(p);
+
+       /* The device responds to return from I/O thread. */
+       dev = new_device("block", VIRTIO_ID_BLOCK, p[0], handle_io_finish);
+
+       /* The device has a virtqueue. */
+       add_virtqueue(dev, VIRTQUEUE_NUM, handle_virtblk_output);
+
+       /* Allocate the room for our own bookkeeping */
+       vblk = dev->priv = malloc(sizeof(*vblk));
+
+       /* First we open the file and store the length. */
+       vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE);
+       vblk->len = lseek64(vblk->fd, 0, SEEK_END);
+
+       /* Tell Guest how many sectors this device has. */
+       cap = cpu_to_le64(vblk->len / 512);
+       add_desc_field(dev, VIRTIO_CONFIG_BLK_F_CAPACITY, sizeof(cap), &cap);
+
+       /* Tell Guest not to put in too many descriptors at once: two are used
+        * for the in and out elements. */
+       val = cpu_to_le32(VIRTQUEUE_NUM - 2);
+       add_desc_field(dev, VIRTIO_CONFIG_BLK_F_SEG_MAX, sizeof(val), &val);
+
+       /* The I/O thread writes to this end of the pipe when done. */
+       vblk->done_fd = p[1];
+
+       /* This is how we tell the I/O thread about more work. */
+       pipe(vblk->workpipe);
+
+       /* Create stack for thread and run it */
+       stack = malloc(32768);
+       if (clone(io_thread, stack + 32768, CLONE_VM, dev) == -1)
+               err(1, "Creating clone");
+
+       /* We don't need to keep the I/O thread's end of the pipes open. */
+       close(vblk->done_fd);
+       close(vblk->workpipe[0]);
+
+       verbose("device %u: virtblock %llu sectors\n",
+               devices.device_num, cap);
+}
 /* That's the end of device setup. */
 
 /*L:220 Finally we reach the core of the Launcher, which runs the Guest, serves
  * its input and output, and finally, lays it to rest. */
-static void __attribute__((noreturn))
-run_guest(int lguest_fd, struct device_list *device_list)
+static void __attribute__((noreturn)) run_guest(int lguest_fd)
 {
        for (;;) {
-               u32 args[] = { LHREQ_BREAK, 0 };
-               unsigned long arr[2];
+               unsigned long args[] = { LHREQ_BREAK, 0 };
+               unsigned long notify_addr;
                int readval;
 
                /* We read from the /dev/lguest device to run the Guest. */
-               readval = read(lguest_fd, arr, sizeof(arr));
-
-               /* The read can only really return sizeof(arr) (the Guest did a
-                * SEND_DMA to us), or an error. */
+               readval = read(lguest_fd, &notify_addr, sizeof(notify_addr));
 
-               /* For a successful read, arr[0] is the address of the "struct
-                * lguest_dma", and arr[1] is the key the Guest sent to. */
-               if (readval == sizeof(arr)) {
-                       handle_output(lguest_fd, arr[0], arr[1], device_list);
+               /* One unsigned long means the Guest did HCALL_NOTIFY */
+               if (readval == sizeof(notify_addr)) {
+                       verbose("Notify on address %#lx\n", notify_addr);
+                       handle_output(lguest_fd, notify_addr);
                        continue;
                /* ENOENT means the Guest died.  Reading tells us why. */
                } else if (errno == ENOENT) {
@@ -1351,7 +1494,7 @@ run_guest(int lguest_fd, struct device_list *device_list)
 
                /* Service input, then unset the BREAK which releases
                 * the Waker. */
-               handle_input(lguest_fd, device_list);
+               handle_input(lguest_fd);
                if (write(lguest_fd, args, sizeof(args)) < 0)
                        err(1, "Resetting break");
        }
@@ -1365,7 +1508,6 @@ run_guest(int lguest_fd, struct device_list *device_list)
 
 static struct option opts[] = {
        { "verbose", 0, NULL, 'v' },
-       { "sharenet", 1, NULL, 's' },
        { "tunnet", 1, NULL, 't' },
        { "block", 1, NULL, 'b' },
        { "initrd", 1, NULL, 'i' },
@@ -1374,37 +1516,21 @@ static struct option opts[] = {
 static void usage(void)
 {
        errx(1, "Usage: lguest [--verbose] "
-            "[--sharenet=<filename>|--tunnet=(<ipaddr>|bridge:<bridgename>)\n"
+            "[--tunnet=(<ipaddr>|bridge:<bridgename>)\n"
             "|--block=<filename>|--initrd=<filename>]...\n"
             "<mem-in-mb> vmlinux [args...]");
 }
 
-/*L:100 The Launcher code itself takes us out into userspace, that scary place
- * where pointers run wild and free!  Unfortunately, like most userspace
- * programs, it's quite boring (which is why everyone like to hack on the
- * kernel!).  Perhaps if you make up an Lguest Drinking Game at this point, it
- * will get you through this section.  Or, maybe not.
- *
- * The Launcher binary sits up high, usually starting at address 0xB8000000.
- * Everything below this is the "physical" memory for the Guest.  For example,
- * if the Guest were to write a "1" at physical address 0, we would see a "1"
- * in the Launcher at "(int *)0".  Guest physical == Launcher virtual.
- *
- * This can be tough to get your head around, but usually it just means that we
- * don't need to do any conversion when the Guest gives us it's "physical"
- * addresses.
- */
+/*L:105 The main routine is where the real work begins: */
 int main(int argc, char *argv[])
 {
-       /* Memory, top-level pagetable, code startpoint, PAGE_OFFSET and size
-        * of the (optional) initrd. */
-       unsigned long mem = 0, pgdir, start, page_offset, initrd_size = 0;
+       /* Memory, top-level pagetable, code startpoint and size of the
+        * (optional) initrd. */
+       unsigned long mem = 0, pgdir, start, initrd_size = 0;
        /* A temporary and the /dev/lguest file descriptor. */
        int i, c, lguest_fd;
-       /* The list of Guest devices, based on command line arguments. */
-       struct device_list device_list;
-       /* The boot information for the Guest: at guest-physical address 0. */
-       void *boot = (void *)0;
+       /* The boot information for the Guest. */
+       struct boot_params *boot;
        /* If they specify an initrd file to load. */
        const char *initrd_name = NULL;
 
@@ -1412,11 +1538,12 @@ int main(int argc, char *argv[])
         * device receive input from a file descriptor, we keep an fdset
         * (infds) and the maximum fd number (max_infd) with the head of the
         * list.  We also keep a pointer to the last device, for easy appending
-        * to the list. */
-       device_list.max_infd = -1;
-       device_list.dev = NULL;
-       device_list.lastdev = &device_list.dev;
-       FD_ZERO(&device_list.infds);
+        * to the list.  Finally, we keep the next interrupt number to hand out
+        * (1: remember that 0 is used by the timer). */
+       FD_ZERO(&devices.infds);
+       devices.max_infd = -1;
+       devices.lastdev = &devices.dev;
+       devices.next_irq = 1;
 
        /* We need to know how much memory so we can set up the device
         * descriptor and memory pages for the devices as we parse the command
@@ -1424,9 +1551,16 @@ int main(int argc, char *argv[])
         * of memory now. */
        for (i = 1; i < argc; i++) {
                if (argv[i][0] != '-') {
-                       mem = top = atoi(argv[i]) * 1024 * 1024;
-                       device_list.descs = map_zeroed_pages(top, 1);
-                       top += getpagesize();
+                       mem = atoi(argv[i]) * 1024 * 1024;
+                       /* We start by mapping anonymous pages over all of
+                        * guest-physical memory range.  This fills it with 0,
+                        * and ensures that the Guest won't be killed when it
+                        * tries to access it. */
+                       guest_base = map_zeroed_pages(mem / getpagesize()
+                                                     + DEVICE_PAGES);
+                       guest_limit = mem;
+                       guest_max = mem + DEVICE_PAGES*getpagesize();
+                       devices.descpage = get_pages(1);
                        break;
                }
        }
@@ -1437,14 +1571,11 @@ int main(int argc, char *argv[])
                case 'v':
                        verbose = true;
                        break;
-               case 's':
-                       setup_net_file(optarg, &device_list);
-                       break;
                case 't':
-                       setup_tun_net(optarg, &device_list);
+                       setup_tun_net(optarg);
                        break;
                case 'b':
-                       setup_block_file(optarg, &device_list);
+                       setup_block_file(optarg);
                        break;
                case 'i':
                        initrd_name = optarg;
@@ -1459,56 +1590,60 @@ int main(int argc, char *argv[])
        if (optind + 2 > argc)
                usage();
 
-       /* We always have a console device */
-       setup_console(&device_list);
+       verbose("Guest base is at %p\n", guest_base);
 
-       /* We start by mapping anonymous pages over all of guest-physical
-        * memory range.  This fills it with 0, and ensures that the Guest
-        * won't be killed when it tries to access it. */
-       map_zeroed_pages(0, mem / getpagesize());
+       /* We always have a console device */
+       setup_console();
 
        /* Now we load the kernel */
-       start = load_kernel(open_or_die(argv[optind+1], O_RDONLY),
-                           &page_offset);
+       start = load_kernel(open_or_die(argv[optind+1], O_RDONLY));
+
+       /* Boot information is stashed at physical address 0 */
+       boot = from_guest_phys(0);
 
        /* Map the initrd image if requested (at top of physical memory) */
        if (initrd_name) {
                initrd_size = load_initrd(initrd_name, mem);
                /* These are the location in the Linux boot header where the
                 * start and size of the initrd are expected to be found. */
-               *(unsigned long *)(boot+0x218) = mem - initrd_size;
-               *(unsigned long *)(boot+0x21c) = initrd_size;
+               boot->hdr.ramdisk_image = mem - initrd_size;
+               boot->hdr.ramdisk_size = initrd_size;
                /* The bootloader type 0xFF means "unknown"; that's OK. */
-               *(unsigned char *)(boot+0x210) = 0xFF;
+               boot->hdr.type_of_loader = 0xFF;
        }
 
        /* Set up the initial linear pagetables, starting below the initrd. */
-       pgdir = setup_pagetables(mem, initrd_size, page_offset);
+       pgdir = setup_pagetables(mem, initrd_size);
 
        /* The Linux boot header contains an "E820" memory map: ours is a
         * simple, single region. */
-       *(char*)(boot+E820NR) = 1;
-       *((struct e820entry *)(boot+E820MAP))
-               = ((struct e820entry) { 0, mem, E820_RAM });
+       boot->e820_entries = 1;
+       boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM });
        /* The boot header contains a command line pointer: we put the command
-        * line after the boot header (at address 4096) */
-       *(void **)(boot + 0x228) = boot + 4096;
-       concat(boot + 4096, argv+optind+2);
+        * line after the boot header. */
+       boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1);
+       concat((char *)(boot + 1), argv+optind+2);
+
+       /* Boot protocol version: 2.07 supports the fields for lguest. */
+       boot->hdr.version = 0x207;
+
+       /* The hardware_subarch value of "1" tells the Guest it's an lguest. */
+       boot->hdr.hardware_subarch = 1;
 
-       /* The guest type value of "1" tells the Guest it's under lguest. */
-       *(int *)(boot + 0x23c) = 1;
+       /* Tell the entry path not to try to reload segment registers. */
+       boot->hdr.loadflags |= KEEP_SEGMENTS;
 
        /* We tell the kernel to initialize the Guest: this returns the open
         * /dev/lguest file descriptor. */
-       lguest_fd = tell_kernel(pgdir, start, page_offset);
+       lguest_fd = tell_kernel(pgdir, start);
 
        /* We fork off a child process, which wakes the Launcher whenever one
         * of the input file descriptors needs attention.  Otherwise we would
         * run the Guest until it tries to output something. */
-       waker_fd = setup_waker(lguest_fd, &device_list);
+       waker_fd = setup_waker(lguest_fd);
 
        /* Finally, run the Guest.  This doesn't return. */
-       run_guest(lguest_fd, &device_list);
+       run_guest(lguest_fd);
 }
 /*:*/
 
index 821617b..7885ab2 100644 (file)
@@ -6,7 +6,7 @@ Lguest is designed to be a minimal hypervisor for the Linux kernel, for
 Linux developers and users to experiment with virtualization with the
 minimum of complexity.  Nonetheless, it should have sufficient
 features to make it useful for specific tasks, and, of course, you are
-encouraged to fork and enhance it.
+encouraged to fork and enhance it (see drivers/lguest/README).
 
 Features:
 
@@ -23,19 +23,30 @@ Developer features:
 
 Running Lguest:
 
-- Lguest runs the same kernel as guest and host.  You can configure
-  them differently, but usually it's easiest not to.
+- The easiest way to run lguest is to use same kernel as guest and host.
+  You can configure them differently, but usually it's easiest not to.
 
   You will need to configure your kernel with the following options:
 
-  CONFIG_HIGHMEM64G=n ("High Memory Support" "64GB")[1]
-  CONFIG_TUN=y/m ("Universal TUN/TAP device driver support")
-  CONFIG_EXPERIMENTAL=y ("Prompt for development and/or incomplete code/drivers")
-  CONFIG_PARAVIRT=y ("Paravirtualization support (EXPERIMENTAL)")
-  CONFIG_LGUEST=y/m ("Linux hypervisor example code")
-
-  and I recommend:
-  CONFIG_HZ=100 ("Timer frequency")[2]
+  "General setup":
+     "Prompt for development and/or incomplete code/drivers" = Y
+        (CONFIG_EXPERIMENTAL=y)
+
+  "Processor type and features":
+     "Paravirtualized guest support" = Y
+        "Lguest guest support" = Y
+     "High Memory Support" = off/4GB
+     "Alignment value to which kernel should be aligned" = 0x100000
+        (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and
+         CONFIG_PHYSICAL_ALIGN=0x100000)
+
+  "Device Drivers":
+     "Network device support"
+        "Universal TUN/TAP device driver support" = M/Y
+           (CONFIG_TUN=m)
+     "Virtualization"
+        "Linux hypervisor example code" = M/Y
+           (CONFIG_LGUEST=m)
 
 - A tool called "lguest" is available in this directory: type "make"
   to build it.  If you didn't build your kernel in-tree, use "make
@@ -51,14 +62,17 @@ Running Lguest:
          dd if=/dev/zero of=rootfile bs=1M count=2048
          qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d
 
+  Make sure that you install a getty on /dev/hvc0 if you want to log in on the
+  console!
+
 - "modprobe lg" if you built it as a module.
 
 - Run an lguest as root:
 
-      Documentation/lguest/lguest 64m vmlinux --tunnet=192.168.19.1 --block=rootfile root=/dev/lgba
+      Documentation/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 --block=rootfile root=/dev/vda
 
    Explanation:
-    64m: the amount of memory to use.
+    64: the amount of memory to use, in MB.
 
     vmlinux: the kernel image found in the top of your build directory.  You
        can also use a standard bzImage.
@@ -66,10 +80,10 @@ Running Lguest:
     --tunnet=192.168.19.1: configures a "tap" device for networking with this
        IP address.
 
-    --block=rootfile: a file or block device which becomes /dev/lgba
+    --block=rootfile: a file or block device which becomes /dev/vda
        inside the guest.
 
-    root=/dev/lgba: this (and anything else on the command line) are
+    root=/dev/vda: this (and anything else on the command line) are
        kernel boot parameters.
 
 - Configuring networking.  I usually have the host masquerade, using
@@ -99,31 +113,7 @@ Running Lguest:
   "--sharenet=<filename>": any two guests using the same file are on
   the same network.  This file is created if it does not exist.
 
-Lguest I/O model:
-
-Lguest uses a simplified DMA model plus shared memory for I/O.  Guests
-can communicate with each other if they share underlying memory
-(usually by the lguest program mmaping the same file), but they can
-use any non-shared memory to communicate with the lguest process.
-
-Guests can register DMA buffers at any key (must be a valid physical
-address) using the LHCALL_BIND_DMA(key, dmabufs, num<<8|irq)
-hypercall.  "dmabufs" is the physical address of an array of "num"
-"struct lguest_dma": each contains a used_len, and an array of
-physical addresses and lengths.  When a transfer occurs, the
-"used_len" field of one of the buffers which has used_len 0 will be
-set to the length transferred and the irq will fire.
+There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest
 
-Using an irq value of 0 unbinds the dma buffers.
-
-To send DMA, the LHCALL_SEND_DMA(key, dma_physaddr) hypercall is used,
-and the bytes used is written to the used_len field.  This can be 0 if
-noone else has bound a DMA buffer to that key or some other error.
-DMA buffers bound by the same guest are ignored.
-
-Cheers!
+Good luck!
 Rusty Russell rusty@rustcorp.com.au.
-
-[1] These are on various places on the TODO list, waiting for you to
-    get annoyed enough at the limitation to fix it.
-[2] Lguest is not yet tickless when idle.  See [1].
index 5fbcc22..168117b 100644 (file)
@@ -2,7 +2,8 @@
 Memory Hotplug
 ==============
 
-Last Updated: Jul 28 2007
+Created:                                       Jul 28 2007
+Add description of notifier of memory hotplug  Oct 11 2007
 
 This document is about memory hotplug including how-to-use and current status.
 Because Memory Hotplug is still under development, contents of this text will
@@ -24,7 +25,8 @@ be changed often.
   6.1 Memory offline and ZONE_MOVABLE
   6.2. How to offline memory
 7. Physical memory remove
-8. Future Work List
+8. Memory hotplug event notifier
+9. Future Work List
 
 Note(1): x86_64's has special implementation for memory hotplug.
          This text does not describe it.
@@ -307,8 +309,58 @@ Need more implementation yet....
  - Notification completion of remove works by OS to firmware.
  - Guard from remove if not yet.
 
+--------------------------------
+8. Memory hotplug event notifier
+--------------------------------
+Memory hotplug has event notifer. There are 6 types of notification.
+
+MEMORY_GOING_ONLINE
+  Generated before new memory becomes available in order to be able to
+  prepare subsystems to handle memory. The page allocator is still unable
+  to allocate from the new memory.
+
+MEMORY_CANCEL_ONLINE
+  Generated if MEMORY_GOING_ONLINE fails.
+
+MEMORY_ONLINE
+  Generated when memory has succesfully brought online. The callback may
+  allocate pages from the new memory.
+
+MEMORY_GOING_OFFLINE
+  Generated to begin the process of offlining memory. Allocations are no
+  longer possible from the memory but some of the memory to be offlined
+  is still in use. The callback can be used to free memory known to a
+  subsystem from the indicated memory section.
+
+MEMORY_CANCEL_OFFLINE
+  Generated if MEMORY_GOING_OFFLINE fails. Memory is available again from
+  the section that we attempted to offline.
+
+MEMORY_OFFLINE
+  Generated after offlining memory is complete.
+
+A callback routine can be registered by
+  hotplug_memory_notifier(callback_func, priority)
+
+The second argument of callback function (action) is event types of above.
+The third argument is passed by pointer of struct memory_notify.
+
+struct memory_notify {
+       unsigned long start_pfn;
+       unsigned long nr_pages;
+       int status_cahnge_nid;
+}
+
+start_pfn is start_pfn of online/offline memory.
+nr_pages is # of pages of online/offline memory.
+status_change_nid is set node id when N_HIGH_MEMORY of nodemask is (will be)
+set/clear. It means a new(memoryless) node gets new memory by online and a
+node loses all memory. If this is -1, then nodemask status is not changed.
+If status_changed_nid >= 0, callback should create/discard structures for the
+node if necessary.
+
 --------------
-8. Future Work
+9. Future Work
 --------------
   - allowing memory hot-add to ZONE_MOVABLE. maybe we need some switch like
     sysctl or new control file.
index 5f7d536..5e03610 100644 (file)
@@ -185,7 +185,7 @@ bestcomm@<addr>     dma-controller          mpc5200-bestcomm 5200 pic also requires
 Recommended soc5200 child nodes; populate as needed for your board
 name           device_type     compatible        Description
 ----           -----------     ----------        -----------
-gpt@<addr>     gpt             mpc5200-gpt       General purpose timers
+gpt@<addr>     gpt             fsl,mpc5200-gpt   General purpose timers
 rtc@<addr>     rtc             mpc5200-rtc       Real time clock
 mscan@<addr>   mscan           mpc5200-mscan     CAN bus controller
 pci@<addr>     pci             mpc5200-pci       PCI bridge
@@ -213,7 +213,7 @@ cell-index  int             When multiple devices are present, is the
 5) General Purpose Timer nodes (child of soc5200 node)
 On the mpc5200 and 5200b, GPT0 has a watchdog timer function.  If the board
 design supports the internal wdt, then the device node for GPT0 should
-include the empty property 'has-wdt'.
+include the empty property 'fsl,has-wdt'.
 
 6) PSC nodes (child of soc5200 node)
 PSC nodes can define the optional 'port-number' property to force assignment
index 4ed4139..40245af 100644 (file)
@@ -1963,11 +1963,6 @@ M:       adaplas@gmail.com
 L:     linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
 S:     Maintained
 
-INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
-P:     Ingo Molnar
-M:     mingo@redhat.com
-S:     Maintained
-
 INTEL I8XX RANDOM NUMBER GENERATOR SUPPORT
 P:     Jeff Garzik
 M:     jgarzik@pobox.com
@@ -2343,6 +2338,8 @@ L:        linuxppc-dev@ozlabs.org
 S:     Maintained
 
 LINUX FOR POWERPC EMBEDDED PPC8XX
+P:     Vitaly Bordug
+M:     vitb@kernel.crashing.org
 P:     Marcelo Tosatti
 M:     marcelo@kvack.org
 W:     http://www.penguinppc.org/
@@ -4269,9 +4266,15 @@ M:       jacmet@sunsite.dk
 L:     linux-serial@vger.kernel.org
 S:     Maintained
 
-X86 3-LEVEL PAGING (PAE) SUPPORT
+X86 ARCHITECTURE (32-BIT AND 64-BIT)
+P:     Thomas Gleixner
+M:     tglx@linutronix.de
 P:     Ingo Molnar
 M:     mingo@redhat.com
+P:     H. Peter Anvin
+M:     hpa@zytor.com
+L:     linux-kernel@vger.kernel.org
+T:     git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
 S:     Maintained
 
 YAM DRIVER FOR AX.25
index f9c264e..264f37b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1505,15 +1505,16 @@ quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN   $(wildcard $(rm-files))
 # and we build for the host arch
 quiet_cmd_depmod = DEPMOD  $(KERNELRELEASE)
       cmd_depmod = \
-       if [ -r System.map -a -x $(DEPMOD) -a "$(SUBARCH)" == "$(ARCH)" ]; then \
+       if [ -r System.map -a -x $(DEPMOD) ]; then                              \
                $(DEPMOD) -ae -F System.map                                     \
                $(if $(strip $(INSTALL_MOD_PATH)), -b $(INSTALL_MOD_PATH) -r)   \
                $(KERNELRELEASE);                                               \
        fi
 
 # Create temporary dir for module support files
-cmd_crmodverdir = $(Q)mkdir -p $(MODVERDIR); rm -f $(MODVERDIR)/*
-
+# clean it up only when building all modules
+cmd_crmodverdir = $(Q)mkdir -p $(MODVERDIR) \
+                  $(if $(KBUILD_MODULES),; rm -f $(MODVERDIR)/*)
 
 a_flags = -Wp,-MD,$(depfile) $(KBUILD_AFLAGS) $(AFLAGS_KERNEL) \
          $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
index e1c4707..2d00a08 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/bootmem.h>
+#include <linux/scatterlist.h>
 #include <linux/log2.h>
 
 #include <asm/io.h>
@@ -465,7 +466,7 @@ EXPORT_SYMBOL(pci_free_consistent);
    Write dma_length of each leader with the combined lengths of
    the mergable followers.  */
 
-#define SG_ENT_VIRT_ADDRESS(SG) (page_address((SG)->page) + (SG)->offset)
+#define SG_ENT_VIRT_ADDRESS(SG) (sg_virt((SG)))
 #define SG_ENT_PHYS_ADDRESS(SG) __pa(SG_ENT_VIRT_ADDRESS(SG))
 
 static void
index 44ab0da..52fc6a8 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/list.h>
+#include <linux/scatterlist.h>
 
 #include <asm/cacheflush.h>
 
@@ -442,7 +443,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        BUG_ON(dir == DMA_NONE);
 
        for (i = 0; i < nents; i++, sg++) {
-               struct page *page = sg->page;
+               struct page *page = sg_page(sg);
                unsigned int offset = sg->offset;
                unsigned int length = sg->length;
                void *ptr = page_address(page) + offset;
index 6b9e466..5be0d13 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/at73c213.h>
 
 #include <video/atmel_lcdc.h>
 
@@ -48,8 +49,27 @@ static struct eth_platform_data __initdata eth_data[2] = {
        },
 };
 
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+static struct at73c213_board_info at73c213_data = {
+       .ssc_id         = 0,
+       .shortname      = "AVR32 STK1000 external DAC",
+};
+#endif
+#endif
+
 #ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
 static struct spi_board_info spi0_board_info[] __initdata = {
+#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+       {
+               /* AT73C213 */
+               .modalias       = "at73c213",
+               .max_speed_hz   = 200000,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_1,
+               .platform_data  = &at73c213_data,
+       },
+#endif
        {
                /* QVGA display */
                .modalias       = "ltv350qv",
@@ -180,6 +200,38 @@ static void setup_j2_leds(void)
 }
 #endif
 
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+static void __init at73c213_set_clk(struct at73c213_board_info *info)
+{
+       struct clk *gclk;
+       struct clk *pll;
+
+       gclk = clk_get(NULL, "gclk0");
+       if (IS_ERR(gclk))
+               goto err_gclk;
+       pll = clk_get(NULL, "pll0");
+       if (IS_ERR(pll))
+               goto err_pll;
+
+       if (clk_set_parent(gclk, pll)) {
+               pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
+               goto err_set_clk;
+       }
+
+       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+       info->dac_clk = gclk;
+
+err_set_clk:
+       clk_put(pll);
+err_pll:
+       clk_put(gclk);
+err_gclk:
+       return;
+}
+#endif
+#endif
+
 void __init setup_board(void)
 {
 #ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
@@ -248,6 +300,12 @@ static int __init atstk1002_init(void)
 
        setup_j2_leds();
 
+#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+       at73c213_set_clk(&at73c213_data);
+#endif
+#endif
+
        return 0;
 }
 postcore_initcall(atstk1002_init);
index f6d154c..a9d9ec0 100644 (file)
@@ -556,6 +556,17 @@ static struct clk pico_clk = {
        .users          = 1,
 };
 
+static struct resource dmaca0_resource[] = {
+       {
+               .start  = 0xff200000,
+               .end    = 0xff20ffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(2),
+};
+DEFINE_DEV(dmaca, 0);
+DEV_CLK(hclk, dmaca0, hsb, 10);
+
 /* --------------------------------------------------------------------
  * HMATRIX
  * -------------------------------------------------------------------- */
@@ -655,6 +666,7 @@ void __init at32_add_system_devices(void)
        platform_device_register(&at32_eic0_device);
        platform_device_register(&smc0_device);
        platform_device_register(&pdc_device);
+       platform_device_register(&dmaca0_device);
 
        platform_device_register(&at32_systc0_device);
 
@@ -959,6 +971,96 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
        return pdev;
 }
 
+/* --------------------------------------------------------------------
+ *  TWI
+ * -------------------------------------------------------------------- */
+static struct resource atmel_twi0_resource[] __initdata = {
+       PBMEM(0xffe00800),
+       IRQ(5),
+};
+static struct clk atmel_twi0_pclk = {
+       .name           = "twi_pclk",
+       .parent         = &pba_clk,
+       .mode           = pba_clk_mode,
+       .get_rate       = pba_clk_get_rate,
+       .index          = 2,
+};
+
+struct platform_device *__init at32_add_device_twi(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (id != 0)
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_twi", id);
+       if (!pdev)
+               return NULL;
+
+       if (platform_device_add_resources(pdev, atmel_twi0_resource,
+                               ARRAY_SIZE(atmel_twi0_resource)))
+               goto err_add_resources;
+
+       select_peripheral(PA(6),  PERIPH_A, 0); /* SDA  */
+       select_peripheral(PA(7),  PERIPH_A, 0); /* SDL  */
+
+       atmel_twi0_pclk.dev = &pdev->dev;
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * MMC
+ * -------------------------------------------------------------------- */
+static struct resource atmel_mci0_resource[] __initdata = {
+       PBMEM(0xfff02400),
+       IRQ(28),
+};
+static struct clk atmel_mci0_pclk = {
+       .name           = "mci_clk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 9,
+};
+
+struct platform_device *__init at32_add_device_mci(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (id != 0)
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_mci", id);
+       if (!pdev)
+               return NULL;
+
+       if (platform_device_add_resources(pdev, atmel_mci0_resource,
+                               ARRAY_SIZE(atmel_mci0_resource)))
+               goto err_add_resources;
+
+       select_peripheral(PA(10), PERIPH_A, 0); /* CLK   */
+       select_peripheral(PA(11), PERIPH_A, 0); /* CMD   */
+       select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
+       select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
+       select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
+       select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
+
+       atmel_mci0_pclk.dev = &pdev->dev;
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
 /* --------------------------------------------------------------------
  *  LCDC
  * -------------------------------------------------------------------- */
@@ -1227,6 +1329,241 @@ out_free_pdev:
        return NULL;
 }
 
+/* --------------------------------------------------------------------
+ * IDE / CompactFlash
+ * -------------------------------------------------------------------- */
+static struct resource at32_smc_cs4_resource[] __initdata = {
+       {
+               .start  = 0x04000000,
+               .end    = 0x07ffffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(~0UL), /* Magic IRQ will be overridden */
+};
+static struct resource at32_smc_cs5_resource[] __initdata = {
+       {
+               .start  = 0x20000000,
+               .end    = 0x23ffffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(~0UL), /* Magic IRQ will be overridden */
+};
+
+static int __init at32_init_ide_or_cf(struct platform_device *pdev,
+               unsigned int cs, unsigned int extint)
+{
+       static unsigned int extint_pin_map[4] __initdata = {
+               GPIO_PIN_PB(25),
+               GPIO_PIN_PB(26),
+               GPIO_PIN_PB(27),
+               GPIO_PIN_PB(28),
+       };
+       static bool common_pins_initialized __initdata = false;
+       unsigned int extint_pin;
+       int ret;
+
+       if (extint >= ARRAY_SIZE(extint_pin_map))
+               return -EINVAL;
+       extint_pin = extint_pin_map[extint];
+
+       switch (cs) {
+       case 4:
+               ret = platform_device_add_resources(pdev,
+                               at32_smc_cs4_resource,
+                               ARRAY_SIZE(at32_smc_cs4_resource));
+               if (ret)
+                       return ret;
+
+               select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
+               set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
+               break;
+       case 5:
+               ret = platform_device_add_resources(pdev,
+                               at32_smc_cs5_resource,
+                               ARRAY_SIZE(at32_smc_cs5_resource));
+               if (ret)
+                       return ret;
+
+               select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
+               set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!common_pins_initialized) {
+               select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1  -> CS0_N */
+               select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2  -> CS1_N */
+               select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW  -> DIR   */
+               select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT  <- IORDY */
+               common_pins_initialized = true;
+       }
+
+       at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+
+       pdev->resource[1].start = EIM_IRQ_BASE + extint;
+       pdev->resource[1].end = pdev->resource[1].start;
+
+       return 0;
+}
+
+struct platform_device *__init
+at32_add_device_ide(unsigned int id, unsigned int extint,
+                   struct ide_platform_data *data)
+{
+       struct platform_device *pdev;
+
+       pdev = platform_device_alloc("at32_ide", id);
+       if (!pdev)
+               goto fail;
+
+       if (platform_device_add_data(pdev, data,
+                               sizeof(struct ide_platform_data)))
+               goto fail;
+
+       if (at32_init_ide_or_cf(pdev, data->cs, extint))
+               goto fail;
+
+       platform_device_add(pdev);
+       return pdev;
+
+fail:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+struct platform_device *__init
+at32_add_device_cf(unsigned int id, unsigned int extint,
+                   struct cf_platform_data *data)
+{
+       struct platform_device *pdev;
+
+       pdev = platform_device_alloc("at32_cf", id);
+       if (!pdev)
+               goto fail;
+
+       if (platform_device_add_data(pdev, data,
+                               sizeof(struct cf_platform_data)))
+               goto fail;
+
+       if (at32_init_ide_or_cf(pdev, data->cs, extint))
+               goto fail;
+
+       if (data->detect_pin != GPIO_PIN_NONE)
+               at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
+       if (data->reset_pin != GPIO_PIN_NONE)
+               at32_select_gpio(data->reset_pin, 0);
+       if (data->vcc_pin != GPIO_PIN_NONE)
+               at32_select_gpio(data->vcc_pin, 0);
+       /* READY is used as extint, so we can't select it as gpio */
+
+       platform_device_add(pdev);
+       return pdev;
+
+fail:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * AC97C
+ * -------------------------------------------------------------------- */
+static struct resource atmel_ac97c0_resource[] __initdata = {
+       PBMEM(0xfff02800),
+       IRQ(29),
+};
+static struct clk atmel_ac97c0_pclk = {
+       .name           = "pclk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 10,
+};
+
+struct platform_device *__init at32_add_device_ac97c(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (id != 0)
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_ac97c", id);
+       if (!pdev)
+               return NULL;
+
+       if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
+                               ARRAY_SIZE(atmel_ac97c0_resource)))
+               goto err_add_resources;
+
+       select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */
+       select_peripheral(PB(21), PERIPH_B, 0); /* SDO  */
+       select_peripheral(PB(22), PERIPH_B, 0); /* SDI  */
+       select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */
+
+       atmel_ac97c0_pclk.dev = &pdev->dev;
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * ABDAC
+ * -------------------------------------------------------------------- */
+static struct resource abdac0_resource[] __initdata = {
+       PBMEM(0xfff02000),
+       IRQ(27),
+};
+static struct clk abdac0_pclk = {
+       .name           = "pclk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .index          = 8,
+};
+static struct clk abdac0_sample_clk = {
+       .name           = "sample_clk",
+       .mode           = genclk_mode,
+       .get_rate       = genclk_get_rate,
+       .set_rate       = genclk_set_rate,
+       .set_parent     = genclk_set_parent,
+       .index          = 6,
+};
+
+struct platform_device *__init at32_add_device_abdac(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (id != 0)
+               return NULL;
+
+       pdev = platform_device_alloc("abdac", id);
+       if (!pdev)
+               return NULL;
+
+       if (platform_device_add_resources(pdev, abdac0_resource,
+                               ARRAY_SIZE(abdac0_resource)))
+               goto err_add_resources;
+
+       select_peripheral(PB(20), PERIPH_A, 0); /* DATA1        */
+       select_peripheral(PB(21), PERIPH_A, 0); /* DATA0        */
+       select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1       */
+       select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0       */
+
+       abdac0_pclk.dev = &pdev->dev;
+       abdac0_sample_clk.dev = &pdev->dev;
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
 /* --------------------------------------------------------------------
  *  GCLK
  * -------------------------------------------------------------------- */
@@ -1290,6 +1627,7 @@ struct clk *at32_clock_list[] = {
        &smc0_mck,
        &pdc_hclk,
        &pdc_pclk,
+       &dmaca0_hclk,
        &pico_clk,
        &pio0_mck,
        &pio1_mck,
@@ -1307,6 +1645,8 @@ struct clk *at32_clock_list[] = {
        &macb1_pclk,
        &atmel_spi0_spi_clk,
        &atmel_spi1_spi_clk,
+       &atmel_twi0_pclk,
+       &atmel_mci0_pclk,
        &atmel_lcdfb0_hck1,
        &atmel_lcdfb0_pixclk,
        &ssc0_pclk,
@@ -1314,6 +1654,9 @@ struct clk *at32_clock_list[] = {
        &ssc2_pclk,
        &usba0_hclk,
        &usba0_pclk,
+       &atmel_ac97c0_pclk,
+       &abdac0_pclk,
+       &abdac0_sample_clk,
        &gclk0,
        &gclk1,
        &gclk2,
@@ -1355,6 +1698,7 @@ void __init at32_clock_init(void)
        genclk_init_parent(&gclk3);
        genclk_init_parent(&gclk4);
        genclk_init_parent(&atmel_lcdfb0_pixclk);
+       genclk_init_parent(&abdac0_sample_clk);
 
        /*
         * Turn on all clocks that have at least one user already, and
index 8acd010..f5bfd4c 100644 (file)
@@ -142,7 +142,7 @@ static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
        return ret;
 }
 
-struct irq_chip eic_chip = {
+static struct irq_chip eic_chip = {
        .name           = "eic",
        .ack            = eic_ack_irq,
        .mask           = eic_mask_irq,
index 47efd0d..694d521 100644 (file)
 
 /* Register access macros */
 #define pm_readl(reg)                                                  \
-       __raw_readl((void __iomem *)AT32_PM_BASE + PM_##reg)
+       __raw_readl((void __iomem __force *)AT32_PM_BASE + PM_##reg)
 #define pm_writel(reg,value)                                           \
-       __raw_writel((value), (void __iomem *)AT32_PM_BASE + PM_##reg)
+       __raw_writel((value), (void __iomem __force *)AT32_PM_BASE + PM_##reg)
 
 #endif /* __ARCH_AVR32_MACH_AT32AP_PM_H__ */
index e3070bd..1026586 100644 (file)
@@ -79,7 +79,7 @@ static int avr32_timer_calc_div_and_set_jiffies(struct clk *pclk)
 {
        unsigned int cycles_max = (clocksource_avr32.mask + 1) / 2;
        unsigned int divs[] = { 4, 8, 16, 32 };
-       int divs_size = sizeof(divs) / sizeof(*divs);
+       int divs_size = ARRAY_SIZE(divs);
        int i = 0;
        unsigned long count_hz;
        unsigned long shift;
index ad28dc7..7888551 100644 (file)
@@ -71,7 +71,7 @@ config GENERIC_CALIBRATE_DELAY
 
 config IRQCHIP_DEMUX_GPIO
        bool
-       depends on (BF53x || BF561 || BF54x)
+       depends on (BF52x || BF53x || BF561 || BF54x)
        default y
 
 source "init/Kconfig"
@@ -85,6 +85,21 @@ choice
        prompt "CPU"
        default BF533
 
+config BF522
+       bool "BF522"
+       help
+         BF522 Processor Support.
+
+config BF525
+       bool "BF525"
+       help
+         BF525 Processor Support.
+
+config BF527
+       bool "BF527"
+       help
+         BF527 Processor Support.
+
 config BF531
        bool "BF531"
        help
@@ -144,13 +159,18 @@ endchoice
 
 choice
        prompt "Silicon Rev"
+       default BF_REV_0_1 if BF527
        default BF_REV_0_2 if BF537
        default BF_REV_0_3 if BF533
        default BF_REV_0_0 if BF549
 
 config BF_REV_0_0
        bool "0.0"
-       depends on (BF549)
+       depends on (BF549 || BF527)
+
+config BF_REV_0_1
+       bool "0.2"
+       depends on (BF549 || BF527)
 
 config BF_REV_0_2
        bool "0.2"
@@ -176,6 +196,11 @@ config BF_REV_NONE
 
 endchoice
 
+config BF52x
+       bool
+       depends on (BF522 || BF525 || BF527)
+       default y
+
 config BF53x
        bool
        depends on (BF531 || BF532 || BF533 || BF534 || BF536 || BF537)
@@ -204,6 +229,12 @@ choice
          configuration to ensure that all the other settings are
          correct.
 
+config BFIN527_EZKIT
+       bool "BF527-EZKIT"
+       depends on (BF522 || BF525 || BF527)
+       help
+         BF533-EZKIT-LITE board Support.
+
 config BFIN533_EZKIT
        bool "BF533-EZKIT"
        depends on (BF533 || BF532 || BF531)
@@ -299,11 +330,17 @@ config MEM_MT48LC8M32B2B5_7
        depends on (BFIN561_BLUETECHNIX_CM)
        default y
 
+config MEM_MT48LC32M16A2TG_75
+       bool
+       depends on (BFIN527_EZKIT)
+       default y
+
 config BFIN_SHARED_FLASH_ENET
        bool
        depends on (BFIN533_STAMP)
        default y
 
+source "arch/blackfin/mach-bf527/Kconfig"
 source "arch/blackfin/mach-bf533/Kconfig"
 source "arch/blackfin/mach-bf561/Kconfig"
 source "arch/blackfin/mach-bf537/Kconfig"
@@ -329,7 +366,7 @@ config CLKIN_HZ
        int "Crystal Frequency in Hz"
        default "11059200" if BFIN533_STAMP
        default "27000000" if BFIN533_EZKIT
-       default "25000000" if BFIN537_STAMP
+       default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT)
        default "30000000" if BFIN561_EZKIT
        default "24576000" if PNAV10
        help
@@ -362,7 +399,7 @@ config VCO_MULT
        range 1 64
        default "22" if BFIN533_EZKIT
        default "45" if BFIN533_STAMP
-       default "20" if BFIN537_STAMP
+       default "20" if (BFIN537_STAMP || BFIN527_EZKIT)
        default "22" if BFIN533_BLUETECHNIX_CM
        default "20" if BFIN537_BLUETECHNIX_CM
        default "20" if BFIN561_BLUETECHNIX_CM
@@ -398,7 +435,7 @@ config SCLK_DIV
        range 1 15
        default 5 if BFIN533_EZKIT
        default 5 if BFIN533_STAMP
-       default 4 if BFIN537_STAMP
+       default 4 if (BFIN537_STAMP || BFIN527_EZKIT)
        default 5 if BFIN533_BLUETECHNIX_CM
        default 4 if BFIN537_BLUETECHNIX_CM
        default 4 if BFIN561_BLUETECHNIX_CM
@@ -450,6 +487,7 @@ comment "Memory Setup"
 config MEM_SIZE
        int "SDRAM Memory Size in MBytes"
        default  32 if BFIN533_EZKIT
+       default  64 if BFIN527_EZKIT
        default  64 if BFIN537_STAMP
        default  64 if BFIN561_EZKIT
        default 128 if BFIN533_STAMP
@@ -459,6 +497,7 @@ config MEM_ADD_WIDTH
        int "SDRAM Memory Address Width"
        default  9 if BFIN533_EZKIT
        default  9 if BFIN561_EZKIT
+       default 10 if BFIN527_EZKIT
        default 10 if BFIN537_STAMP
        default 11 if BFIN533_STAMP
        default 10 if PNAV10
@@ -749,9 +788,19 @@ config LARGE_ALLOCS
          a lot of RAM, and you need to able to allocate very large
          contiguous chunks. If unsure, say N.
 
+config BFIN_GPTIMERS
+       tristate "Enable Blackfin General Purpose Timers API"
+       default n
+       help
+         Enable support for the General Purpose Timers API.  If you
+         are unsure, say N.
+
+         To compile this driver as a module, choose M here: the module
+         will be called gptimers.ko.
+
 config BFIN_DMA_5XX
        bool "Enable DMA Support"
-       depends on (BF533 || BF532 || BF531 || BF537 || BF536 || BF534 || BF561 || BF54x)
+       depends on (BF52x || BF53x || BF561 || BF54x)
        default y
        help
          DMA driver for BF5xx.
index 3689337..f7cac7c 100644 (file)
@@ -12,12 +12,17 @@ LDFLAGS_vmlinux  := -X
 OBJCOPYFLAGS     := -O binary -R .note -R .comment -S
 GZFLAGS          := -9
 
+KBUILD_CFLAGS           += $(call cc-option,-mno-fdpic)
+KBUILD_AFLAGS           += $(call cc-option,-mno-fdpic)
 CFLAGS_MODULE    += -mlong-calls
 KALLSYMS         += --symbol-prefix=_
 
 KBUILD_DEFCONFIG := BF537-STAMP_defconfig
 
 # setup the machine name and the machine dependent settings
+machine-$(CONFIG_BF522) := bf527
+machine-$(CONFIG_BF525) := bf527
+machine-$(CONFIG_BF527) := bf527
 machine-$(CONFIG_BF531) := bf533
 machine-$(CONFIG_BF532) := bf533
 machine-$(CONFIG_BF533) := bf533
@@ -32,6 +37,9 @@ machine-$(CONFIG_BF561) := bf561
 MACHINE := $(machine-y)
 export MACHINE
 
+cpu-$(CONFIG_BF522) := bf522
+cpu-$(CONFIG_BF525) := bf525
+cpu-$(CONFIG_BF527) := bf527
 cpu-$(CONFIG_BF531) := bf531
 cpu-$(CONFIG_BF532) := bf532
 cpu-$(CONFIG_BF533) := bf533
@@ -97,12 +105,23 @@ archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
 
 
-all: vmImage
 boot := arch/$(ARCH)/boot
 BOOT_TARGETS = vmImage
-.PHONY: $(BOOT_TARGETS)
+PHONY += $(BOOT_TARGETS) install
+KBUILD_IMAGE := $(boot)/vmImage
+
+all: vmImage
+
 $(BOOT_TARGETS): vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+install:
+       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
+
 define archhelp
   echo  '* vmImage         - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage)'
+  echo  '  install         - Install kernel using'
+  echo  '                     (your) ~/bin/$(CROSS_COMPILE)installkernel or'
+  echo  '                     (distribution) PATH: $(CROSS_COMPILE)installkernel or'
+  echo  '                     install to $$(INSTALL_PATH)'
 endef
index 8cd3356..522f3c1 100644 (file)
@@ -26,3 +26,6 @@ $(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
 $(obj)/vmImage: $(obj)/vmlinux.gz
        $(call if_changed,uimage)
        @echo 'Kernel: $@ is ready'
+
+install:
+       sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
diff --git a/arch/blackfin/boot/install.sh b/arch/blackfin/boot/install.sh
new file mode 100644 (file)
index 0000000..9560a6b
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# arch/blackfin/boot/install.sh
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+# Adapted from code in arch/i386/boot/install.sh by Mike Frysinger
+#
+# "make install" script for Blackfin architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+verify () {
+       if [ ! -f "$1" ]; then
+               echo ""                                                   1>&2
+               echo " *** Missing file: $1"                              1>&2
+               echo ' *** You need to run "make" before "make install".' 1>&2
+               echo ""                                                   1>&2
+               exit 1
+       fi
+}
+
+# Make sure the files actually exist
+verify "$2"
+verify "$3"
+
+# User may have a custom install script
+
+if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi
+if which ${CROSS_COMPILE}installkernel >/dev/null 2>&1; then
+       exec ${CROSS_COMPILE}installkernel "$@"
+fi
+
+# Default install - same as make zlilo
+
+back_it_up() {
+       local file=$1
+       [ -f ${file} ] || return 0
+       local stamp=$(stat -c %Y ${file} 2>/dev/null)
+       mv ${file} ${file}.${stamp:-old}
+}
+
+back_it_up $4/uImage
+back_it_up $4/System.map
+
+cat $2 > $4/uImage
+cp $3 $4/System.map
diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
new file mode 100644 (file)
index 0000000..df974e7
--- /dev/null
@@ -0,0 +1,1241 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22.9
+#
+# 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_ZONE_DMA=y
+CONFIG_BFIN=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_IRQCHIP_DEMUX_GPIO=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# 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
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF525 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_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_0_0=y
+# 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_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF52x=y
+CONFIG_BFIN_SINGLE_CORE=y
+CONFIG_BFIN527_EZKIT=y
+# CONFIG_BFIN533_EZKIT is not set
+# CONFIG_BFIN533_STAMP is not set
+# CONFIG_BFIN537_STAMP is not set
+# CONFIG_BFIN533_BLUETECHNIX_CM is not set
+# CONFIG_BFIN537_BLUETECHNIX_CM is not set
+# CONFIG_BFIN548_EZKIT is not set
+# CONFIG_BFIN561_BLUETECHNIX_CM is not set
+# CONFIG_BFIN561_EZKIT is not set
+# CONFIG_BFIN561_TEPLA is not set
+# CONFIG_PNAV10 is not set
+# CONFIG_GENERIC_BOARD is not set
+CONFIG_MEM_MT48LC32M16A2TG_75=y
+
+#
+# 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 is not set
+CONFIG_BF527_UART1_PORTG=y
+# CONFIG_BF527_NAND_D_PORTF is not set
+CONFIG_BF527_NAND_D_PORTH=y
+
+#
+# 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_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_SPI=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_TMR0=12
+CONFIG_IRQ_TMR1=12
+CONFIG_IRQ_TMR2=12
+CONFIG_IRQ_TMR3=12
+CONFIG_IRQ_TMR4=12
+CONFIG_IRQ_TMR5=12
+CONFIG_IRQ_TMR6=12
+CONFIG_IRQ_TMR7=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_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
+
+#
+# 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=133000000
+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
+
+#
+# Memory Setup
+#
+CONFIG_MEM_SIZE=64
+CONFIG_MEM_ADD_WIDTH=10
+CONFIG_BOOT_LOAD=0x1000
+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_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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_LARGE_ALLOCS=y
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+# CONFIG_BFIN_WB is not set
+CONFIG_BFIN_WT=y
+CONFIG_L1_MAX_PIECE=16
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMBCTL 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=0x5554
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0xFFC0
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# 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_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_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_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG 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
+
+#
+# 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
+
+#
+# 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_MW320D=m
+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_BF5xx=m
+CONFIG_BFIN_FLASH_SIZE=0x400000
+CONFIG_EBIU_FLASH_BASE=0x20000000
+# 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_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_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
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN 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_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+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_SMSC911X is not set
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=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_UINPUT is not set
+# CONFIG_BF53X_PFBUTTONS is not set
+# CONFIG_TWI_KEYPAD is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PFLAGS is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BF5xx_TIMERS is not set
+# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPORT is not set
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_TWI_LCD is not set
+# CONFIG_AD5304 is not set
+# CONFIG_BF5xx_TEA5764 is not set
+# CONFIG_BF5xx_FBDMA is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+# CONFIG_SERIAL_BFIN_DMA is not set
+CONFIG_SERIAL_BFIN_PIO=y
+# 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_LEGACY_PTYS is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_BFIN_WDT=y
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_BLACKFIN_GPIO is not set
+CONFIG_I2C_BLACKFIN_TWI=m
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_AD5252 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8575 is not set
+# CONFIG_SENSORS_PCA9543 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BFIN=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_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_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
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_BFIN=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# 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_CHECKPOINT_RESERVED_BLOCKS=10
+# 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_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_SUNRPC_BIND34 is not set
+# 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
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_MMRS=y
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index e80f3d5..d856988 100644 (file)
@@ -809,7 +809,14 @@ CONFIG_UNIX98_PTYS=y
 # IPMI
 #
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG 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_HW_RANDOM=y
 # CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
index 8aeb606..8a4cfb2 100644 (file)
@@ -9,6 +9,7 @@ obj-y := \
        sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \
        fixed_code.o cplbinit.o cacheinit.o reboot.o bfin_gpio.o
 
+obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
 obj-$(CONFIG_MODULES)                += module.o
 obj-$(CONFIG_BFIN_DMA_5XX)           += bfin_dma_5xx.o
 obj-$(CONFIG_DUAL_CORE_TEST_MODULE)  += dualcore_test.o
index e19164f..503eef4 100644 (file)
@@ -420,6 +420,32 @@ unsigned short get_dma_curr_ycount(unsigned int channel)
 }
 EXPORT_SYMBOL(get_dma_curr_ycount);
 
+unsigned long get_dma_next_desc_ptr(unsigned int channel)
+{
+       BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+             && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+       return dma_ch[channel].regs->next_desc_ptr;
+}
+EXPORT_SYMBOL(get_dma_next_desc_ptr);
+
+unsigned long get_dma_curr_desc_ptr(unsigned int channel)
+{
+       BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+             && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+       return dma_ch[channel].regs->curr_desc_ptr;
+}
+
+unsigned long get_dma_curr_addr(unsigned int channel)
+{
+       BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+             && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+       return dma_ch[channel].regs->curr_addr_ptr;
+}
+EXPORT_SYMBOL(get_dma_curr_addr);
+
 static void *__dma_memcpy(void *dest, const void *src, size_t size)
 {
        int direction;  /* 1 - address decrease, 0 - address increase */
index 3fe0cd4..ce85d4b 100644 (file)
@@ -124,7 +124,7 @@ static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
 };
 #endif
 
-#ifdef BF537_FAMILY
+#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
 static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
        (struct gpio_port_t *) PORTFIO,
        (struct gpio_port_t *) PORTGIO,
@@ -139,6 +139,21 @@ static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
 
 #endif
 
+#ifdef BF527_FAMILY
+static unsigned short *port_mux[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+       (unsigned short *) PORTF_MUX,
+       (unsigned short *) PORTG_MUX,
+       (unsigned short *) PORTH_MUX,
+};
+
+static const
+u8 pmux_offset[][16] =
+       {{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 4, 6, 8, 8, 10, 10 }, /* PORTF */
+        { 0, 0, 0, 0, 0, 2, 2, 4, 4, 6, 8, 10, 10, 10, 12, 12 }, /* PORTG */
+        { 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 4, 4, 4, 4, 4 }, /* PORTH */
+       };
+#endif
+
 #ifdef BF561_FAMILY
 static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
        (struct gpio_port_t *) FIO0_FLAG_D,
@@ -186,6 +201,10 @@ static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB
 static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX};
 #endif
 
+#ifdef BF527_FAMILY
+static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PORTF_INTB, IRQ_PORTG_INTB, IRQ_PORTH_INTB};
+#endif
+
 #ifdef BF561_FAMILY
 static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB};
 #endif
@@ -238,7 +257,7 @@ static int cmp_label(unsigned short ident, const char *label)
                return -EINVAL;
 }
 
-#ifdef BF537_FAMILY
+#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
 static void port_setup(unsigned short gpio, unsigned short usage)
 {
        if (!check_gpio(gpio)) {
@@ -354,6 +373,18 @@ inline u16 get_portmux(unsigned short portno)
 
        return (pmux >> (2 * gpio_sub_n(portno)) & 0x3);
 }
+#elif defined(BF527_FAMILY)
+inline void portmux_setup(unsigned short portno, unsigned short function)
+{
+       u16 pmux, ident = P_IDENT(portno);
+       u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)];
+
+       pmux = *port_mux[gpio_bank(ident)];
+       pmux &= ~(3 << offset);
+       pmux |= (function & 3) << offset;
+       *port_mux[gpio_bank(ident)] = pmux;
+       SSYNC();
+}
 #else
 # define portmux_setup(...)  do { } while (0)
 #endif
index 94d7b11..a16cb03 100644 (file)
@@ -160,8 +160,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        BUG_ON(direction == DMA_NONE);
 
        for (i = 0; i < nents; i++, sg++) {
-               sg->dma_address = (dma_addr_t)(page_address(sg->page) +
-                                       sg->offset);
+               sg->dma_address = (dma_addr_t) sg_virt(sg);
 
                invalidate_dcache_range(sg_dma_address(sg),
                                        sg_dma_address(sg) +
diff --git a/arch/blackfin/kernel/gptimers.c b/arch/blackfin/kernel/gptimers.c
new file mode 100644 (file)
index 0000000..cb7ba9b
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * bfin_gptimers.c - derived from bf53x_timers.c
+ *  Driver for General Purpose Timer functions on the Blackfin processor
+ *
+ *  Copyright (C) 2005 John DeHority
+ *  Copyright (C) 2006 Hella Aglaia GmbH (awe@aglaia-gmbh.de)
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/blackfin.h>
+#include <asm/gptimers.h>
+
+#ifdef DEBUG
+# define tassert(expr)
+#else
+# define tassert(expr) \
+       if (!(expr)) \
+               printk(KERN_DEBUG "%s:%s:%i: Assertion failed: " #expr "\n", \
+                       __FILE__, __func__, __LINE__);
+#endif
+
+#define BFIN_TIMER_NUM_GROUP  (BFIN_TIMER_OCTET(MAX_BLACKFIN_GPTIMERS - 1) + 1)
+
+typedef struct {
+       uint16_t config;
+       uint16_t __pad;
+       uint32_t counter;
+       uint32_t period;
+       uint32_t width;
+} GPTIMER_timer_regs;
+
+typedef struct {
+       uint16_t enable;
+       uint16_t __pad0;
+       uint16_t disable;
+       uint16_t __pad1;
+       uint32_t status;
+} GPTIMER_group_regs;
+
+static volatile GPTIMER_timer_regs *const timer_regs[MAX_BLACKFIN_GPTIMERS] =
+{
+       (GPTIMER_timer_regs *)TIMER0_CONFIG,
+       (GPTIMER_timer_regs *)TIMER1_CONFIG,
+       (GPTIMER_timer_regs *)TIMER2_CONFIG,
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+       (GPTIMER_timer_regs *)TIMER3_CONFIG,
+       (GPTIMER_timer_regs *)TIMER4_CONFIG,
+       (GPTIMER_timer_regs *)TIMER5_CONFIG,
+       (GPTIMER_timer_regs *)TIMER6_CONFIG,
+       (GPTIMER_timer_regs *)TIMER7_CONFIG,
+#endif
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+       (GPTIMER_timer_regs *)TIMER8_CONFIG,
+       (GPTIMER_timer_regs *)TIMER9_CONFIG,
+       (GPTIMER_timer_regs *)TIMER10_CONFIG,
+       (GPTIMER_timer_regs *)TIMER11_CONFIG,
+#endif
+};
+
+static volatile GPTIMER_group_regs *const group_regs[BFIN_TIMER_NUM_GROUP] =
+{
+       (GPTIMER_group_regs *)TIMER0_GROUP_REG,
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+       (GPTIMER_group_regs *)TIMER8_GROUP_REG,
+#endif
+};
+
+static uint32_t const dis_mask[MAX_BLACKFIN_GPTIMERS] =
+{
+       TIMER_STATUS_TRUN0,
+       TIMER_STATUS_TRUN1,
+       TIMER_STATUS_TRUN2,
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+       TIMER_STATUS_TRUN3,
+       TIMER_STATUS_TRUN4,
+       TIMER_STATUS_TRUN5,
+       TIMER_STATUS_TRUN6,
+       TIMER_STATUS_TRUN7,
+#endif
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+       TIMER_STATUS_TRUN8,
+       TIMER_STATUS_TRUN9,
+       TIMER_STATUS_TRUN10,
+       TIMER_STATUS_TRUN11,
+#endif
+};
+
+static uint32_t const irq_mask[MAX_BLACKFIN_GPTIMERS] =
+{
+       TIMER_STATUS_TIMIL0,
+       TIMER_STATUS_TIMIL1,
+       TIMER_STATUS_TIMIL2,
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+       TIMER_STATUS_TIMIL3,
+       TIMER_STATUS_TIMIL4,
+       TIMER_STATUS_TIMIL5,
+       TIMER_STATUS_TIMIL6,
+       TIMER_STATUS_TIMIL7,
+#endif
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+       TIMER_STATUS_TIMIL8,
+       TIMER_STATUS_TIMIL9,
+       TIMER_STATUS_TIMIL10,
+       TIMER_STATUS_TIMIL11,
+#endif
+};
+
+void set_gptimer_pwidth(int timer_id, uint32_t value)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       timer_regs[timer_id]->width = value;
+       SSYNC();
+}
+EXPORT_SYMBOL(set_gptimer_pwidth);
+
+uint32_t get_gptimer_pwidth(int timer_id)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       return timer_regs[timer_id]->width;
+}
+EXPORT_SYMBOL(get_gptimer_pwidth);
+
+void set_gptimer_period(int timer_id, uint32_t period)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       timer_regs[timer_id]->period = period;
+       SSYNC();
+}
+EXPORT_SYMBOL(set_gptimer_period);
+
+uint32_t get_gptimer_period(int timer_id)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       return timer_regs[timer_id]->period;
+}
+EXPORT_SYMBOL(get_gptimer_period);
+
+uint32_t get_gptimer_count(int timer_id)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       return timer_regs[timer_id]->counter;
+}
+EXPORT_SYMBOL(get_gptimer_count);
+
+uint32_t get_gptimer_status(int group)
+{
+       tassert(group < BFIN_TIMER_NUM_GROUP);
+       return group_regs[group]->status;
+}
+EXPORT_SYMBOL(get_gptimer_status);
+
+void set_gptimer_status(int group, uint32_t value)
+{
+       tassert(group < BFIN_TIMER_NUM_GROUP);
+       group_regs[group]->status = value;
+       SSYNC();
+}
+EXPORT_SYMBOL(set_gptimer_status);
+
+uint16_t get_gptimer_intr(int timer_id)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       return (group_regs[BFIN_TIMER_OCTET(timer_id)]->status & irq_mask[timer_id]) ? 1 : 0;
+}
+EXPORT_SYMBOL(get_gptimer_intr);
+
+void clear_gptimer_intr(int timer_id)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       group_regs[BFIN_TIMER_OCTET(timer_id)]->status = irq_mask[timer_id];
+}
+EXPORT_SYMBOL(clear_gptimer_intr);
+
+void set_gptimer_config(int timer_id, uint16_t config)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       timer_regs[timer_id]->config = config;
+       SSYNC();
+}
+EXPORT_SYMBOL(set_gptimer_config);
+
+uint16_t get_gptimer_config(int timer_id)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       return timer_regs[timer_id]->config;
+}
+EXPORT_SYMBOL(get_gptimer_config);
+
+void enable_gptimers(uint16_t mask)
+{
+       int i;
+       tassert((mask & ~BLACKFIN_GPTIMER_IDMASK) == 0);
+       for (i = 0; i < BFIN_TIMER_NUM_GROUP; ++i) {
+               group_regs[i]->enable = mask & 0xFF;
+               mask >>= 8;
+       }
+       SSYNC();
+}
+EXPORT_SYMBOL(enable_gptimers);
+
+void disable_gptimers(uint16_t mask)
+{
+       int i;
+       uint16_t m = mask;
+       tassert((mask & ~BLACKFIN_GPTIMER_IDMASK) == 0);
+       for (i = 0; i < BFIN_TIMER_NUM_GROUP; ++i) {
+               group_regs[i]->disable = m & 0xFF;
+               m >>= 8;
+       }
+       for (i = 0; i < MAX_BLACKFIN_GPTIMERS; ++i)
+               if (mask & (1 << i))
+                       group_regs[BFIN_TIMER_OCTET(i)]->status |= dis_mask[i];
+       SSYNC();
+}
+EXPORT_SYMBOL(disable_gptimers);
+
+void set_gptimer_pulse_hi(int timer_id)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       timer_regs[timer_id]->config |= TIMER_PULSE_HI;
+       SSYNC();
+}
+EXPORT_SYMBOL(set_gptimer_pulse_hi);
+
+void clear_gptimer_pulse_hi(int timer_id)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       timer_regs[timer_id]->config &= ~TIMER_PULSE_HI;
+       SSYNC();
+}
+EXPORT_SYMBOL(clear_gptimer_pulse_hi);
+
+uint16_t get_enabled_gptimers(void)
+{
+       int i;
+       uint16_t result = 0;
+       for (i = 0; i < BFIN_TIMER_NUM_GROUP; ++i)
+               result |= (group_regs[i]->enable << (i << 3));
+       return result;
+}
+EXPORT_SYMBOL(get_enabled_gptimers);
+
+MODULE_AUTHOR("Axel Weiss (awe@aglaia-gmbh.de)");
+MODULE_DESCRIPTION("Blackfin General Purpose Timers API");
+MODULE_LICENSE("GPL");
index 356078e..ae28aac 100644 (file)
@@ -11,7 +11,7 @@
 #include <asm/reboot.h>
 #include <asm/system.h>
 
-#if defined(BF537_FAMILY) || defined(BF533_FAMILY)
+#if defined(BF537_FAMILY) || defined(BF533_FAMILY) || defined(BF527_FAMILY)
 #define SYSCR_VAL      0x0
 #elif defined(BF561_FAMILY)
 #define SYSCR_VAL      0x20
index 8dcd76e..f1b059e 100644 (file)
@@ -459,7 +459,7 @@ static u_long get_vco(void)
        return vco;
 }
 
-/*Get the Core clock*/
+/* Get the Core clock */
 u_long get_cclk(void)
 {
        u_long csel, ssel;
@@ -493,12 +493,24 @@ u_long get_sclk(void)
 }
 EXPORT_SYMBOL(get_sclk);
 
+unsigned long sclk_to_usecs(unsigned long sclk)
+{
+       return (USEC_PER_SEC * (u64)sclk) / get_sclk();
+}
+EXPORT_SYMBOL(sclk_to_usecs);
+
+unsigned long usecs_to_sclk(unsigned long usecs)
+{
+       return (get_sclk() * (u64)usecs) / USEC_PER_SEC;
+}
+EXPORT_SYMBOL(usecs_to_sclk);
+
 /*
  *     Get CPU information for use by the procfs.
  */
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
-       char *cpu, *mmu, *fpu, *name;
+       char *cpu, *mmu, *fpu, *vendor, *cache;
        uint32_t revid;
 
        u_long cclk = 0, sclk = 0;
@@ -508,70 +520,83 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        mmu = "none";
        fpu = "none";
        revid = bfin_revid();
-       name = bfin_board_name;
 
        cclk = get_cclk();
        sclk = get_sclk();
 
-       seq_printf(m, "CPU:\t\tADSP-%s Rev. 0.%d\n"
-                  "MMU:\t\t%s\n"
-                  "FPU:\t\t%s\n"
-                  "Core Clock:\t%9lu Hz\n"
-                  "System Clock:\t%9lu Hz\n"
-                  "BogoMips:\t%lu.%02lu\n"
-                  "Calibration:\t%lu loops\n",
-                  cpu, revid, mmu, fpu,
-                  cclk,
-                  sclk,
-                  (loops_per_jiffy * HZ) / 500000,
-                  ((loops_per_jiffy * HZ) / 5000) % 100,
-                  (loops_per_jiffy * HZ));
-       seq_printf(m, "Board Name:\t%s\n", name);
-       seq_printf(m, "Board Memory:\t%ld MB\n", physical_mem_end >> 20);
-       seq_printf(m, "Kernel Memory:\t%ld MB\n", (unsigned long)_ramend >> 20);
-       if (bfin_read_IMEM_CONTROL() & (ENICPLB | IMC))
-               seq_printf(m, "I-CACHE:\tON\n");
-       else
-               seq_printf(m, "I-CACHE:\tOFF\n");
-       if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE))
-               seq_printf(m, "D-CACHE:\tON"
-#if defined CONFIG_BFIN_WB
-                          " (write-back)"
-#elif defined CONFIG_BFIN_WT
-                          " (write-through)"
-#endif
-                          "\n");
-       else
-               seq_printf(m, "D-CACHE:\tOFF\n");
-
+       switch (bfin_read_CHIPID() & CHIPID_MANUFACTURE) {
+       case 0xca:
+               vendor = "Analog Devices";
+               break;
+       default:
+               vendor = "unknown";
+               break;
+       }
 
+       seq_printf(m, "processor\t: %d\n"
+               "vendor_id\t: %s\n"
+               "cpu family\t: 0x%x\n"
+               "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK)\n"
+               "stepping\t: %d\n",
+               0,
+               vendor,
+               (bfin_read_CHIPID() & CHIPID_FAMILY),
+               cpu, cclk/1000000, sclk/1000000,
+               revid);
+
+       seq_printf(m, "cpu MHz\t\t: %lu.%03lu/%lu.%03lu\n",
+               cclk/1000000, cclk%1000000,
+               sclk/1000000, sclk%1000000);
+       seq_printf(m, "bogomips\t: %lu.%02lu\n"
+               "Calibration\t: %lu loops\n",
+               (loops_per_jiffy * HZ) / 500000,
+               ((loops_per_jiffy * HZ) / 5000) % 100,
+               (loops_per_jiffy * HZ));
+
+       /* Check Cache configutation */
        switch (bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) {
        case ACACHE_BSRAM:
-               seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n");
+               cache = "dbank-A/B\t: cache/sram";
                dcache_size = 16;
                dsup_banks = 1;
                break;
        case ACACHE_BCACHE:
-               seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n");
+               cache = "dbank-A/B\t: cache/cache";
                dcache_size = 32;
                dsup_banks = 2;
                break;
        case ASRAM_BSRAM:
-               seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n");
+               cache = "dbank-A/B\t: sram/sram";
                dcache_size = 0;
                dsup_banks = 0;
                break;
        default:
+               cache = "unknown";
+               dcache_size = 0;
+               dsup_banks = 0;
                break;
        }
 
+       /* Is it turned on? */
+       if (!((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE)))
+               dcache_size = 0;
 
-       seq_printf(m, "I-CACHE Size:\t%dKB\n", BFIN_ICACHESIZE / 1024);
-       seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size);
-       seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n",
+       seq_printf(m, "cache size\t: %d KB(L1 icache) "
+               "%d KB(L1 dcache-%s) %d KB(L2 cache)\n",
+               BFIN_ICACHESIZE / 1024, dcache_size,
+#if defined CONFIG_BFIN_WB
+               "wb"
+#elif defined CONFIG_BFIN_WT
+               "wt"
+#endif
+               "", 0);
+
+       seq_printf(m, "%s\n", cache);
+
+       seq_printf(m, "icache setup\t: %d Sub-banks/%d Ways, %d Lines/Way\n",
                   BFIN_ISUBBANKS, BFIN_IWAYS, BFIN_ILINES);
        seq_printf(m,
-                  "D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n",
+                  "dcache setup\t: %d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n",
                   dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS,
                   BFIN_DLINES);
 #ifdef CONFIG_BFIN_ICACHE_LOCK
@@ -625,6 +650,15 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                seq_printf(m, "No Ways are locked\n");
        }
 #endif
+
+       seq_printf(m, "board name\t: %s\n", bfin_board_name);
+       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,
+               (void *)memory_end);
+
        return 0;
 }
 
index 8823e9a..afd044e 100644 (file)
@@ -118,12 +118,14 @@ static int printk_address(unsigned long address)
                                        offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
 
                                write_unlock_irq(&tasklist_lock);
+                               mmput(mm);
                                return printk("<0x%p> [ %s + 0x%lx ]",
                                              (void *)address, name, offset);
                        }
 
                        vml = vml->next;
                }
+               mmput(mm);
        }
        write_unlock_irq(&tasklist_lock);
 
index 635288f..bfdad52 100644 (file)
@@ -4,7 +4,7 @@
 
 lib-y := \
        ashldi3.o ashrdi3.o lshrdi3.o \
-       muldi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
+       muldi3.o divsi3.o udivsi3.o udivdi3.o modsi3.o umodsi3.o \
        checksum.o memcpy.o memset.o memcmp.o memchr.o memmove.o \
        strcmp.o strcpy.o strncmp.o strncpy.o \
        umulsi3_highpart.o smulsi3_highpart.o \
diff --git a/arch/blackfin/lib/udivdi3.S b/arch/blackfin/lib/udivdi3.S
new file mode 100644 (file)
index 0000000..ad1ebee
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * udivdi3.S - unsigned long long division
+ *
+ * Copyright 2003-2007 Analog Devices Inc.
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/linkage.h>
+
+#define CARRY AC0
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+
+ENTRY(___udivdi3)
+   R3 = [SP + 12];
+   [--SP] = (R7:4, P5:3);
+
+   /* Attempt to use divide primitive first; these will handle
+   **  most cases, and they're quick - avoids stalls incurred by
+   ** testing for identities.
+   */
+
+   R4 = R2 | R3;
+   CC = R4 == 0;
+   IF CC JUMP .LDIV_BY_ZERO;
+
+   R4.H = 0x8000;
+   R4 >>>= 16;                  // R4 now 0xFFFF8000
+   R5 = R0 | R2;                // If either dividend or
+   R4 = R5 & R4;                // divisor have bits in
+   CC = R4;                     // top half or low half's sign
+   IF CC JUMP .LIDENTS;          // bit, skip builtins.
+   R4 = R1 | R3;                // Also check top halves
+   CC = R4;
+   IF CC JUMP .LIDENTS;
+
+   /* Can use the builtins. */
+
+   AQ = CC;                     // Clear AQ (CC==0)
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   DIVQ(R0, R2);
+   R0 = R0.L (Z);
+   R1 = 0;
+   (R7:4, P5:3) = [SP++];
+   RTS;
+
+.LIDENTS:
+   /* Test for common identities. Value to be returned is
+   ** placed in R6,R7.
+   */
+                                // Check for 0/y, return 0
+   R4 = R0 | R1;
+   CC = R4 == 0;
+   IF CC JUMP .LRETURN_R0;
+
+                                // Check for x/x, return 1
+   R6 = R0 - R2;                // If x == y, then both R6 and R7 will be zero
+   R7 = R1 - R3;
+   R4 = R6 | R7;                // making R4 zero.
+   R6 += 1;                     // which would now make R6:R7==1.
+   CC = R4 == 0;
+   IF CC JUMP .LRETURN_IDENT;
+
+                                // Check for x/1, return x
+   R6 = R0;
+   R7 = R1;
+   CC = R3 == 0;
+   IF !CC JUMP .Lnexttest;
+   CC = R2 == 1;
+   IF CC JUMP .LRETURN_IDENT;
+
+.Lnexttest:
+   R4.L = ONES R2;              // check for div by power of two which
+   R5.L = ONES R3;              // can be done using a shift
+   R6 = PACK (R5.L, R4.L);
+   CC = R6 == 1;
+   IF CC JUMP .Lpower_of_two_upper_zero;
+   R6 = PACK (R4.L, R5.L);
+   CC = R6 == 1;
+   IF CC JUMP .Lpower_of_two_lower_zero;
+
+                                // Check for x < y, return 0
+   R6 = 0;
+   R7 = R6;
+   CC = R1 < R3 (IU);
+   IF CC JUMP .LRETURN_IDENT;
+   CC = R1 == R3;
+   IF !CC JUMP .Lno_idents;
+   CC = R0 < R2 (IU);
+   IF CC JUMP .LRETURN_IDENT;
+
+.Lno_idents:                    // Idents don't match. Go for the full operation
+
+
+   // If X, or X and Y have high bit set, it'll affect the
+   // results, so shift right one to stop this. Note: we've already
+   // checked that X >= Y, so Y's msb won't be set unless X's
+   // is.
+
+   R4 = 0;
+   CC = R1 < 0;
+   IF !CC JUMP .Lx_msb_clear;
+   CC = !CC;                   // 1 -> 0;
+   R1 = ROT R1 BY -1;          // Shift X >> 1
+   R0 = ROT R0 BY -1;          // lsb -> CC
+   BITSET(R4,31);              // to record only x msb was set
+   CC = R3 < 0;
+   IF !CC JUMP .Ly_msb_clear;
+   CC = !CC;
+   R3 = ROT R3 BY -1;          // Shift Y >> 1
+   R2 = ROT R2 BY -1;
+   BITCLR(R4,31);              // clear bit to record only x msb was set
+
+.Ly_msb_clear:
+.Lx_msb_clear:
+   // Bit 31 in R4 indicates X msb set, but Y msb wasn't, and no bits
+   // were lost, so we should shift result left by one.
+
+   [--SP] = R4;                // save for later
+
+   // In the loop that follows, each iteration we add
+   // either Y' or -Y' to the Remainder. We compute the
+   // negated Y', and store, for convenience. Y' goes
+   // into P0:P1, while -Y' goes into P2:P3.
+
+   P0 = R2;
+   P1 = R3;
+   R2 = -R2;
+   CC = CARRY;
+   CC = !CC;
+   R4 = CC;
+   R3 = -R3;
+   R3 = R3 - R4;
+
+   R6 = 0;                     // remainder = 0
+   R7 = R6;
+
+   [--SP] = R2; P2 = SP;
+   [--SP] = R3; P3 = SP;
+   [--SP] = R6; P5 = SP;       // AQ = 0
+   [--SP] = P1;
+
+   /* In the loop that follows, we use the following
+   ** register assignments:
+   ** R0,R1 X, workspace
+   ** R2,R3 Y, workspace
+   ** R4,R5 partial Div
+   ** R6,R7 partial remainder
+   ** P5 AQ
+   ** The remainder and div form a 128-bit number, with
+   ** the remainder in the high 64-bits.
+   */
+   R4 = R0;                    // Div = X'
+   R5 = R1;
+   R3 = 0;
+
+   P4 = 64;                    // Iterate once per bit
+   LSETUP(.LULST,.LULEND) LC0 = P4;
+.LULST:
+        /* Shift Div and remainder up by one. The bit shifted
+        ** out of the top of the quotient is shifted into the bottom
+        ** of the remainder.
+        */
+        CC = R3;
+        R4 = ROT R4 BY 1;
+        R5 = ROT R5 BY 1 ||        // low q to high q
+             R2 = [P5];            // load saved AQ
+        R6 = ROT R6 BY 1 ||        // high q to low r
+             R0 = [P2];            // load -Y'
+        R7 = ROT R7 BY 1 ||        // low r to high r
+             R1 = [P3];
+
+                                   // Assume add -Y'
+        CC = R2 < 0;               // But if AQ is set...
+        IF CC R0 = P0;             // then add Y' instead
+        IF CC R1 = P1;
+
+        R6 = R6 + R0;              // Rem += (Y' or -Y')
+        CC = CARRY;
+        R0 = CC;
+        R7 = R7 + R1;
+        R7 = R7 + R0 (NS) ||
+             R1 = [SP];
+                                   // Set the next AQ bit
+        R1 = R7 ^ R1;              // from Remainder and Y'
+        R1 = R1 >> 31 ||           // Negate AQ's value, and
+             [P5] = R1;            // save next AQ
+        BITTGL(R1, 0);             // add neg AQ  to the Div
+.LULEND: R4 = R4 + R1;
+
+   R6 = [SP + 16];
+
+   R0 = R4;
+   R1 = R5;
+   CC = BITTST(R6,30);         // Just set CC=0
+   R4 = ROT R0 BY 1;           // but if we had to shift X,
+   R5 = ROT R1 BY 1;           // and didn't shift any bits out,
+   CC = BITTST(R6,31);         // then the result will be half as
+   IF CC R0 = R4;              // much as required, so shift left
+   IF CC R1 = R5;              // one space.
+
+   SP += 20;
+   (R7:4, P5:3) = [SP++];
+   RTS;
+
+.Lpower_of_two:
+   /* Y has a single bit set, which means it's a power of two.
+   ** That means we can perform the division just by shifting
+   ** X to the right the appropriate number of bits
+   */
+
+   /* signbits returns the number of sign bits, minus one.
+   ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
+   ** to shift right n-signbits spaces. It also means 0x80000000
+   ** is a special case, because that *also* gives a signbits of 0
+   */
+.Lpower_of_two_lower_zero:
+   R7 = 0;
+   R6 = R1 >> 31;
+   CC = R3 < 0;
+   IF CC JUMP .LRETURN_IDENT;
+
+   R2.L = SIGNBITS R3;
+   R2 = R2.L (Z);
+   R2 += -62;
+   (R7:4, P5:3) = [SP++];
+   JUMP ___lshftli;
+
+.Lpower_of_two_upper_zero:
+   CC = R2 < 0;
+   IF CC JUMP .Lmaxint_shift;
+
+   R2.L = SIGNBITS R2;
+   R2 = R2.L (Z);
+   R2 += -30;
+   (R7:4, P5:3) = [SP++];
+   JUMP ___lshftli;
+
+.Lmaxint_shift:
+   R2 = -31;
+   (R7:4, P5:3) = [SP++];
+   JUMP ___lshftli;
+
+.LRETURN_IDENT:
+   R0 = R6;
+   R1 = R7;
+.LRETURN_R0:
+   (R7:4, P5:3) = [SP++];
+   RTS;
+.LDIV_BY_ZERO:
+   R0 = ~R2;
+   R1 = R0;
+   (R7:4, P5:3) = [SP++];
+   RTS;
+
+ENDPROC(___udivdi3)
+
+
+ENTRY(___lshftli)
+       CC = R2 == 0;
+       IF CC JUMP .Lfinished;  // nothing to do
+       CC = R2 < 0;
+       IF CC JUMP .Lrshift;
+       R3 = 64;
+       CC = R2 < R3;
+       IF !CC JUMP .Lretzero;
+
+       // We're shifting left, and it's less than 64 bits, so
+       // a valid result will be returned.
+
+       R3 >>= 1;       // R3 now 32
+       CC = R2 < R3;
+
+       IF !CC JUMP .Lzerohalf;
+
+       // We're shifting left, between 1 and 31 bits, which means
+       // some of the low half will be shifted into the high half.
+       // Work out how much.
+
+       R3 = R3 - R2;
+
+       // Save that much data from the bottom half.
+
+       P1 = R7;
+       R7 = R0;
+       R7 >>= R3;
+
+       // Adjust both parts of the parameter.
+
+       R0 <<= R2;
+       R1 <<= R2;
+
+       // And include the bits moved across.
+
+       R1 = R1 | R7;
+       R7 = P1;
+       RTS;
+
+.Lzerohalf:
+       // We're shifting left, between 32 and 63 bits, so the
+       // bottom half will become zero, and the top half will
+       // lose some bits. How many?
+
+       R2 = R2 - R3;   // N - 32
+       R1 = LSHIFT R0 BY R2.L;
+       R0 = R0 - R0;
+       RTS;
+
+.Lretzero:
+       R0 = R0 - R0;
+       R1 = R0;
+.Lfinished:
+       RTS;
+
+.Lrshift:
+       // We're shifting right, but by how much?
+       R2 = -R2;
+       R3 = 64;
+       CC = R2 < R3;
+       IF !CC JUMP .Lretzero;
+
+       // Shifting right less than 64 bits, so some result bits will
+       // be retained.
+
+       R3 >>= 1;       // R3 now 32
+       CC = R2 < R3;
+       IF !CC JUMP .Lsignhalf;
+
+       // Shifting right between 1 and 31 bits, so need to copy
+       // data across words.
+
+       P1 = R7;
+       R3 = R3 - R2;
+       R7 = R1;
+       R7 <<= R3;
+       R1 >>= R2;
+       R0 >>= R2;
+       R0 = R7 | R0;
+       R7 = P1;
+       RTS;
+
+.Lsignhalf:
+       // Shifting right between 32 and 63 bits, so the top half
+       // will become all zero-bits, and the bottom half is some
+       // of the top half. But how much?
+
+       R2 = R2 - R3;
+       R0 = R1;
+       R0 >>= R2;
+       R1 = 0;
+       RTS;
+
+ENDPROC(___lshftli)
diff --git a/arch/blackfin/mach-bf527/Kconfig b/arch/blackfin/mach-bf527/Kconfig
new file mode 100644 (file)
index 0000000..50321f7
--- /dev/null
@@ -0,0 +1,251 @@
+if (BF52x)
+
+menu "BF527 Specific Configuration"
+
+comment "Alternative Multiplexing Scheme"
+
+choice
+       prompt "SPORT0"
+       default BF527_SPORT0_PORTG
+       help
+         Select PORT used for SPORT0. See Hardware Reference Manual
+
+config BF527_SPORT0_PORTF
+       bool "PORT F"
+       help
+         PORT F
+
+config BF527_SPORT0_PORTG
+       bool "PORT G"
+       help
+         PORT G
+endchoice
+
+choice
+       prompt "SPORT0 TSCLK Location"
+       depends on BF527_SPORT0_PORTG
+       default BF527_SPORT0_TSCLK_PG10
+       help
+         Select PIN used for SPORT0_TSCLK. See Hardware Reference Manual
+
+config BF527_SPORT0_TSCLK_PG10
+       bool "PORT PG10"
+       help
+         PORT PG10
+
+config BF527_SPORT0_TSCLK_PG14
+       bool "PORT PG14"
+       help
+         PORT PG14
+endchoice
+
+choice
+       prompt "UART1"
+       default BF527_UART1_PORTG
+       help
+         Select PORT used for UART1. See Hardware Reference Manual
+
+config BF527_UART1_PORTF
+       bool "PORT F"
+       help
+         PORT F
+
+config BF527_UART1_PORTG
+       bool "PORT G"
+       help
+         PORT G
+endchoice
+
+choice
+       prompt "NAND (NFC) Data"
+       default BF527_NAND_D_PORTH
+       help
+         Select PORT used for NAND Data Bus. See Hardware Reference Manual
+
+config BF527_NAND_D_PORTF
+       bool "PORT F"
+       help
+         PORT F
+
+config BF527_NAND_D_PORTH
+       bool "PORT H"
+       help
+         PORT H
+endchoice
+
+comment "Interrupt Priority Assignment"
+menu "Priority"
+
+config IRQ_PLL_WAKEUP
+       int "IRQ_PLL_WAKEUP"
+       default 7
+config IRQ_DMA0_ERROR
+       int "IRQ_DMA0_ERROR"
+       default 7
+config IRQ_DMAR0_BLK
+       int "IRQ_DMAR0_BLK"
+       default 7
+config IRQ_DMAR1_BLK
+       int "IRQ_DMAR1_BLK"
+       default 7
+config IRQ_DMAR0_OVR
+       int "IRQ_DMAR0_OVR"
+       default 7
+config IRQ_DMAR1_OVR
+       int "IRQ_DMAR1_OVR"
+       default 7
+config IRQ_PPI_ERROR
+       int "IRQ_PPI_ERROR"
+       default 7
+config IRQ_MAC_ERROR
+       int "IRQ_MAC_ERROR"
+       default 7
+config IRQ_SPORT0_ERROR
+       int "IRQ_SPORT0_ERROR"
+       default 7
+config IRQ_SPORT1_ERROR
+       int "IRQ_SPORT1_ERROR"
+       default 7
+config IRQ_UART0_ERROR
+       int "IRQ_UART0_ERROR"
+       default 7
+config IRQ_UART1_ERROR
+       int "IRQ_UART1_ERROR"
+       default 7
+config IRQ_RTC
+       int "IRQ_RTC"
+       default 8
+config IRQ_PPI
+       int "IRQ_PPI"
+       default 8
+config IRQ_SPORT0_RX
+       int "IRQ_SPORT0_RX"
+       default 9
+config IRQ_SPORT0_TX
+       int "IRQ_SPORT0_TX"
+       default 9
+config IRQ_SPORT1_RX
+       int "IRQ_SPORT1_RX"
+       default 9
+config IRQ_SPORT1_TX
+       int "IRQ_SPORT1_TX"
+       default 9
+config IRQ_TWI
+       int "IRQ_TWI"
+       default 10
+config IRQ_SPI
+       int "IRQ_SPI"
+       default 10
+config IRQ_UART0_RX
+       int "IRQ_UART0_RX"
+       default 10
+config IRQ_UART0_TX
+       int "IRQ_UART0_TX"
+       default 10
+config IRQ_UART1_RX
+       int "IRQ_UART1_RX"
+       default 10
+config IRQ_UART1_TX
+       int "IRQ_UART1_TX"
+       default 10
+config IRQ_OPTSEC
+       int "IRQ_OPTSEC"
+       default 11
+config IRQ_CNT
+       int "IRQ_CNT"
+       default 11
+config IRQ_MAC_RX
+       int "IRQ_MAC_RX"
+       default 11
+config IRQ_PORTH_INTA
+       int "IRQ_PORTH_INTA"
+       default 11
+config IRQ_MAC_TX
+       int "IRQ_MAC_TX/NFC"
+       default 11
+config IRQ_PORTH_INTB
+       int "IRQ_PORTH_INTB"
+       default 11
+config IRQ_TMR0
+       int "IRQ_TMR0"
+       default 12
+config IRQ_TMR1
+       int "IRQ_TMR1"
+       default 12
+config IRQ_TMR2
+       int "IRQ_TMR2"
+       default 12
+config IRQ_TMR3
+       int "IRQ_TMR3"
+       default 12
+config IRQ_TMR4
+       int "IRQ_TMR4"
+       default 12
+config IRQ_TMR5
+       int "IRQ_TMR5"
+       default 12
+config IRQ_TMR6
+       int "IRQ_TMR6"
+       default 12
+config IRQ_TMR7
+       int "IRQ_TMR7"
+       default 12
+config IRQ_PORTG_INTA
+       int "IRQ_PORTG_INTA"
+       default 12
+config IRQ_PORTG_INTB
+       int "IRQ_PORTG_INTB"
+       default 12
+config IRQ_MEM_DMA0
+       int "IRQ_MEM_DMA0"
+       default 13
+config IRQ_MEM_DMA1
+       int "IRQ_MEM_DMA1"
+       default 13
+config IRQ_WATCH
+       int "IRQ_WATCH"
+       default 13
+config IRQ_PORTF_INTA
+       int "IRQ_PORTF_INTA"
+       default 13
+config IRQ_PORTF_INTB
+       int "IRQ_PORTF_INTB"
+       default 13
+config IRQ_SPI_ERROR
+       int "IRQ_SPI_ERROR"
+       default 7
+config IRQ_NFC_ERROR
+       int "IRQ_NFC_ERROR"
+       default 7
+config IRQ_HDMA_ERROR
+       int "IRQ_HDMA_ERROR"
+       default 7
+config IRQ_HDMA
+       int "IRQ_HDMA"
+       default 7
+config IRQ_USB_EINT
+       int "IRQ_USB_EINT"
+       default 10
+config IRQ_USB_INT0
+       int "IRQ_USB_INT0"
+       default 10
+config IRQ_USB_INT1
+       int "IRQ_USB_INT1"
+       default 10
+config IRQ_USB_INT2
+       int "IRQ_USB_INT2"
+       default 10
+config IRQ_USB_DMA
+       int "IRQ_USB_DMA"
+       default 10
+
+       help
+         Enter the priority numbers between 7-13 ONLY.  Others are Reserved.
+         This applies to all the above.  It is not recommended to assign the
+         highest priority number 7 to UART or any other device.
+
+endmenu
+
+endmenu
+
+endif
diff --git a/arch/blackfin/mach-bf527/Makefile b/arch/blackfin/mach-bf527/Makefile
new file mode 100644 (file)
index 0000000..9f99f5d
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf527/Makefile
+#
+
+extra-y := head.o
+
+obj-y := ints-priority.o dma.o
+
+obj-$(CONFIG_CPU_FREQ)   += cpu.o
diff --git a/arch/blackfin/mach-bf527/boards/Makefile b/arch/blackfin/mach-bf527/boards/Makefile
new file mode 100644 (file)
index 0000000..912ac8e
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# arch/blackfin/mach-bf532/boards/Makefile
+#
+
+obj-y                                  += eth_mac.o
+obj-$(CONFIG_BFIN527_EZKIT)            += ezkit.o
+
diff --git a/arch/blackfin/mach-bf527/boards/eth_mac.c b/arch/blackfin/mach-bf527/boards/eth_mac.c
new file mode 100644 (file)
index 0000000..a725cc8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  arch/blackfin/mach-bf537/board/eth_mac.c
+ *
+ *  Copyright (C) 2007 Analog Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <asm/blackfin.h>
+
+#if    defined(CONFIG_GENERIC_BOARD) || defined(CONFIG_BFIN537_STAMP)
+
+/*
+ * Currently the MAC address is saved in Flash by U-Boot
+ */
+#define FLASH_MAC      0x203f0000
+
+void get_bf537_ether_addr(char *addr)
+{
+       unsigned int flash_mac = (unsigned int) FLASH_MAC;
+       *(u32 *)(&(addr[0])) = bfin_read32(flash_mac);
+       flash_mac += 4;
+       *(u16 *)(&(addr[4])) = bfin_read16(flash_mac);
+}
+
+#else
+
+/*
+ * Provide MAC address function for other specific board setting
+ */
+void get_bf537_ether_addr(char *addr)
+{
+       printk(KERN_WARNING "%s: No valid Ethernet MAC address found\n", __FILE__);
+}
+
+#endif
+
+EXPORT_SYMBOL(get_bf537_ether_addr);
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
new file mode 100644 (file)
index 0000000..3e884f3
--- /dev/null
@@ -0,0 +1,737 @@
+/*
+ * File:         arch/blackfin/mach-bf527/boards/ezkit.c
+ * Based on:     arch/blackfin/mach-bf537/boards/stamp.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+#include <linux/usb_isp1362.h>
+#endif
+#include <linux/pata_platform.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb_sl811.h>
+#include <asm/dma.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/reboot.h>
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+const char bfin_board_name[] = "ADDS-BF527-EZKIT";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#define ISP1761_BASE       0x203C0000
+#define ISP1761_IRQ        IRQ_PF7
+
+#if defined(CONFIG_USB_ISP1760_HCD) || defined(CONFIG_USB_ISP1760_HCD_MODULE)
+static struct resource bfin_isp1761_resources[] = {
+       [0] = {
+               .name   = "isp1761-regs",
+               .start  = ISP1761_BASE + 0x00000000,
+               .end    = ISP1761_BASE + 0x000fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = ISP1761_IRQ,
+               .end    = ISP1761_IRQ,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_isp1761_device = {
+       .name           = "isp1761",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(bfin_isp1761_resources),
+       .resource       = bfin_isp1761_resources,
+};
+
+static struct platform_device *bfin_isp1761_devices[] = {
+       &bfin_isp1761_device,
+};
+
+int __init bfin_isp1761_init(void)
+{
+       unsigned int num_devices = ARRAY_SIZE(bfin_isp1761_devices);
+
+       printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+       set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
+
+       return platform_add_devices(bfin_isp1761_devices, num_devices);
+}
+
+void __exit bfin_isp1761_exit(void)
+{
+       platform_device_unregister(&bfin_isp1761_device);
+}
+
+arch_initcall(bfin_isp1761_init);
+#endif
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+static struct resource bfin_pcmcia_cf_resources[] = {
+       {
+               .start = 0x20310000, /* IO PORT */
+               .end = 0x20312000,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = 0x20311000, /* Attribute Memory */
+               .end = 0x20311FFF,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = IRQ_PF4,
+               .end = IRQ_PF4,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+       }, {
+               .start = 6, /* Card Detect PF6 */
+               .end = 6,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_pcmcia_cf_device = {
+       .name = "bfin_cf_pcmcia",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
+       .resource = bfin_pcmcia_cf_resources,
+};
+#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_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+       {
+               .name = "smc91x-regs",
+               .start = 0x20300300,
+               .end = 0x20300300 + 16,
+               .flags = IORESOURCE_MEM,
+       }, {
+
+               .start = IRQ_PF7,
+               .end = IRQ_PF7,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       },
+};
+static struct platform_device smc91x_device = {
+       .name = "smc91x",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(smc91x_resources),
+       .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
+static struct resource dm9000_resources[] = {
+       [0] = {
+               .start  = 0x203FB800,
+               .end    = 0x203FB800 + 8,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_PF9,
+               .end    = IRQ_PF9,
+               .flags  = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE),
+       },
+};
+
+static struct platform_device dm9000_device = {
+       .name           = "dm9000",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(dm9000_resources),
+       .resource       = dm9000_resources,
+};
+#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);
+
+       if (is_on)
+               gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
+       else
+               gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
+}
+#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_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+       {
+               .start = 0x20360000,
+               .end = 0x20360000,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = 0x20360004,
+               .end = 0x20360004,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+               .end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       },
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+       .sel15Kres = 1,
+       .clknotstop = 0,
+       .oc_enable = 0,
+       .int_act_high = 0,
+       .int_edge_triggered = 0,
+       .remote_wakeup_connected = 0,
+       .no_power_switching = 1,
+       .power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+       .name = "isp1362-hcd",
+       .id = 0,
+       .dev = {
+               .platform_data = &isp1362_priv,
+       },
+       .num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+       .resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+       .name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+       {
+               .start = 0x20300000,
+               .end = 0x20300000 + 0x100,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = IRQ_PF7,
+               .end = IRQ_PF7,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       },
+};
+
+static struct platform_device net2272_bfin_device = {
+       .name = "net2272",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(net2272_bfin_resources),
+       .resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) \
+       || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+       {
+               .name = "bootloader",
+               .size = 0x00020000,
+               .offset = 0,
+               .mask_flags = MTD_CAP_ROM
+       }, {
+               .name = "kernel",
+               .size = 0xe0000,
+               .offset = 0x20000
+       }, {
+               .name = "file system",
+               .size = 0x700000,
+               .offset = 0x00100000,
+       }
+};
+
+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 = "m25p64",
+};
+
+/* 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_SPI_ADC_BF533) \
+       || defined(CONFIG_SPI_ADC_BF533_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_SND_BLACKFIN_AD1836) \
+       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+       .enable_dma = 1,
+       .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+       .ctl_reg        = 0x4, /* send zero */
+       .enable_dma     = 0,
+       .bits_per_word  = 8,
+       .cs_change_per_word = 1,
+};
+#endif
+
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+static struct bfin5xx_spi_chip ad5304_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 16,
+};
+#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
+
+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 = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+               .platform_data = &bfin_spi_flash_data,
+               .controller_data = &spi_flash_chip_info,
+               .mode = SPI_MODE_3,
+       },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+       || defined(CONFIG_SPI_ADC_BF533_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_SND_BLACKFIN_AD1836) \
+       || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+       {
+               .modalias = "ad1836-spi",
+               .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+               .controller_data = &ad1836_spi_chip_info,
+       },
+#endif
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+       {
+               .modalias = "ad9960-spi",
+               .max_speed_hz = 10000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 1,
+               .controller_data = &ad9960_spi_chip_info,
+       },
+#endif
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+       {
+               .modalias = "spi_mmc_dummy",
+               .max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 0,
+               .platform_data = NULL,
+               .controller_data = &spi_mmc_chip_info,
+               .mode = SPI_MODE_3,
+       },
+       {
+               .modalias = "spi_mmc",
+               .max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = CONFIG_SPI_MMC_CS_CHAN,
+               .platform_data = NULL,
+               .controller_data = &spi_mmc_chip_info,
+               .mode = SPI_MODE_3,
+       },
+#endif
+#if defined(CONFIG_PBX)
+       {
+               .modalias = "fxs-spi",
+               .max_speed_hz = 12500000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 8 - CONFIG_J11_JUMPER,
+               .controller_data = &spi_si3xxx_chip_info,
+               .mode = SPI_MODE_3,
+       },
+       {
+               .modalias = "fxo-spi",
+               .max_speed_hz = 12500000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 8 - CONFIG_J19_JUMPER,
+               .controller_data = &spi_si3xxx_chip_info,
+               .mode = SPI_MODE_3,
+       },
+#endif
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+       {
+               .modalias = "ad5304_spi",
+               .max_speed_hz = 1250000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 2,
+               .platform_data = NULL,
+               .controller_data = &ad5304_chip_info,
+               .mode = SPI_MODE_2,
+       },
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+       {
+               .modalias               = "ad7877",
+               .platform_data          = &bfin_ad7877_ts_info,
+               .irq                    = IRQ_PF6,
+               .max_speed_hz   = 12500000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num        = 1,
+               .chip_select  = 1,
+               .controller_data = &spi_ad7877_chip_info,
+       },
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master bfin_spi0_info = {
+       .num_chipselect = 8,
+       .enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+/* SPI (0) */
+static struct resource bfin_spi0_resource[] = {
+       [0] = {
+               .start = SPI0_REGBASE,
+               .end   = SPI0_REGBASE + 0xFF,
+               .flags = IORESOURCE_MEM,
+               },
+       [1] = {
+               .start = CH_SPI,
+               .end   = CH_SPI,
+               .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 */
+       },
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+static struct platform_device bfin_fb_device = {
+       .name = "bf537-lq035",
+};
+#endif
+
+#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
+static struct platform_device bfin_fb_adv7393_device = {
+       .name = "bfin-adv7393",
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       {
+               .start = 0xFFC00400,
+               .end = 0xFFC004FF,
+               .flags = IORESOURCE_MEM,
+       },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       {
+               .start = 0xFFC02000,
+               .end = 0xFFC020FF,
+               .flags = IORESOURCE_MEM,
+       },
+#endif
+};
+
+static struct platform_device bfin_uart_device = {
+       .name = "bfin-uart",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_uart_resources),
+       .resource = bfin_uart_resources,
+};
+#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
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+       .name = "bfin-sport-uart",
+       .id = 1,
+};
+#endif
+
+#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+#define PATA_INT       55
+
+static struct pata_platform_info bfin_pata_platform_data = {
+       .ioport_shift = 1,
+       .irq_type = IRQF_TRIGGER_HIGH | IRQF_DISABLED,
+};
+
+static struct resource bfin_pata_resources[] = {
+       {
+               .start = 0x20314020,
+               .end = 0x2031403F,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = 0x2031401C,
+               .end = 0x2031401F,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = PATA_INT,
+               .end = PATA_INT,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_pata_device = {
+       .name = "pata_platform",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(bfin_pata_resources),
+       .resource = bfin_pata_resources,
+       .dev = {
+               .platform_data = &bfin_pata_platform_data,
+       }
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+       &bfin_pcmcia_cf_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+       &rtc_device,
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+       &sl811_hcd_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+       &isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+       &smc91x_device,
+#endif
+
+#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
+       &dm9000_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+       &bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+       &net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+       &bfin_spi0_device,
+#endif
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+       &bfin_fb_device,
+#endif
+
+#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
+       &bfin_fb_adv7393_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+       &bfin_uart_device,
+#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)
+       &bfin_sport0_uart_device,
+       &bfin_sport1_uart_device,
+#endif
+
+#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+       &bfin_pata_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+       printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+       platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+       spi_register_board_info(bfin_spi_board_info,
+                               ARRAY_SIZE(bfin_spi_board_info));
+#endif
+
+#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+       irq_desc[PATA_INT].status |= IRQ_NOAUTOEN;
+#endif
+       return 0;
+}
+
+arch_initcall(stamp_init);
+
+void native_machine_restart(char *cmd)
+{
+       /* workaround reboot hang when booting from SPI */
+       if ((bfin_read_SYSCR() & 0x7) == 0x3)
+               bfin_gpio_reset_spi0_ssel1();
+}
diff --git a/arch/blackfin/mach-bf527/cpu.c b/arch/blackfin/mach-bf527/cpu.c
new file mode 100644 (file)
index 0000000..1975402
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * File:         arch/blackfin/mach-bf527/cpu.c
+ * Based on:   arch/blackfin/mach-bf537/cpu.c
+ * Author:       michael.kang@analog.com
+ *
+ * Created:
+ * Description:  clock scaling for the bf527
+ *
+ * Modified:
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <asm/dpmc.h>
+#include <linux/fs.h>
+#include <asm/bfin-global.h>
+
+/* CONFIG_CLKIN_HZ=11059200 */
+#define VCO5 (CONFIG_CLKIN_HZ*45)      /*497664000 */
+#define VCO4 (CONFIG_CLKIN_HZ*36)      /*398131200 */
+#define VCO3 (CONFIG_CLKIN_HZ*27)      /*298598400 */
+#define VCO2 (CONFIG_CLKIN_HZ*18)      /*199065600 */
+#define VCO1 (CONFIG_CLKIN_HZ*9)       /*99532800 */
+#define VCO(x) VCO##x
+
+#define MFREQ(x) {VCO(x), VCO(x)/4}, {VCO(x), VCO(x)/2}, {VCO(x), VCO(x)}
+/* frequency */
+static struct cpufreq_frequency_table bf527_freq_table[] = {
+       MFREQ(1),
+       MFREQ(3),
+       {VCO4, VCO4 / 2}, {VCO4, VCO4},
+       MFREQ(5),
+       {0, CPUFREQ_TABLE_END},
+};
+
+/*
+ * dpmc_fops->ioctl()
+ * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+ */
+static int bf527_getfreq(unsigned int cpu)
+{
+       unsigned long cclk_mhz;
+
+       /* The driver only support single cpu */
+       if (cpu == 0)
+               dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
+       else
+               cclk_mhz = -1;
+
+       return cclk_mhz;
+}
+
+static int bf527_target(struct cpufreq_policy *policy,
+                       unsigned int target_freq, unsigned int relation)
+{
+       unsigned long cclk_mhz;
+       unsigned long vco_mhz;
+       unsigned long flags;
+       unsigned int index;
+       struct cpufreq_freqs freqs;
+
+       if (cpufreq_frequency_table_target
+           (policy, bf527_freq_table, target_freq, relation, &index))
+               return -EINVAL;
+
+       cclk_mhz = bf527_freq_table[index].frequency;
+       vco_mhz = bf527_freq_table[index].index;
+
+       dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
+       freqs.old = bf527_getfreq(0);
+       freqs.new = cclk_mhz;
+       freqs.cpu = 0;
+
+       pr_debug
+           ("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
+            cclk_mhz, vco_mhz, index, target_freq, freqs.old);
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+       local_irq_save(flags);
+       dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
+       local_irq_restore(flags);
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       vco_mhz = get_vco();
+       cclk_mhz = get_cclk();
+       return 0;
+}
+
+/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
+ * this platform, anyway.
+ */
+static int bf527_verify_speed(struct cpufreq_policy *policy)
+{
+       return cpufreq_frequency_table_verify(policy, &bf527_freq_table);
+}
+
+static int __init __bf527_cpu_init(struct cpufreq_policy *policy)
+{
+       if (policy->cpu != 0)
+               return -EINVAL;
+
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+       /*Now ,only support one cpu */
+       policy->cur = bf527_getfreq(0);
+       cpufreq_frequency_table_get_attr(bf527_freq_table, policy->cpu);
+       return cpufreq_frequency_table_cpuinfo(policy, bf527_freq_table);
+}
+
+static struct freq_attr *bf527_freq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+static struct cpufreq_driver bf527_driver = {
+       .verify = bf527_verify_speed,
+       .target = bf527_target,
+       .get = bf527_getfreq,
+       .init = __bf527_cpu_init,
+       .name = "bf527",
+       .owner = THIS_MODULE,
+       .attr = bf527_freq_attr,
+};
+
+static int __init bf527_cpu_init(void)
+{
+       return cpufreq_register_driver(&bf527_driver);
+}
+
+static void __exit bf527_cpu_exit(void)
+{
+       cpufreq_unregister_driver(&bf527_driver);
+}
+
+MODULE_AUTHOR("Mickael Kang");
+MODULE_DESCRIPTION("cpufreq driver for bf527 CPU");
+MODULE_LICENSE("GPL");
+
+module_init(bf527_cpu_init);
+module_exit(bf527_cpu_exit);
diff --git a/arch/blackfin/mach-bf527/dma.c b/arch/blackfin/mach-bf527/dma.c
new file mode 100644 (file)
index 0000000..522de24
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * File:         arch/blackfin/mach-bf527/dma.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+
+struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+       (struct dma_register *) DMA0_NEXT_DESC_PTR,
+       (struct dma_register *) DMA1_NEXT_DESC_PTR,
+       (struct dma_register *) DMA2_NEXT_DESC_PTR,
+       (struct dma_register *) DMA3_NEXT_DESC_PTR,
+       (struct dma_register *) DMA4_NEXT_DESC_PTR,
+       (struct dma_register *) DMA5_NEXT_DESC_PTR,
+       (struct dma_register *) DMA6_NEXT_DESC_PTR,
+       (struct dma_register *) DMA7_NEXT_DESC_PTR,
+       (struct dma_register *) DMA8_NEXT_DESC_PTR,
+       (struct dma_register *) DMA9_NEXT_DESC_PTR,
+       (struct dma_register *) DMA10_NEXT_DESC_PTR,
+       (struct dma_register *) DMA11_NEXT_DESC_PTR,
+       (struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
+       (struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
+       (struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
+       (struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
+};
+
+int channel2irq(unsigned int channel)
+{
+       int ret_irq = -1;
+
+       switch (channel) {
+       case CH_PPI:
+               ret_irq = IRQ_PPI;
+               break;
+
+       case CH_EMAC_RX:
+               ret_irq = IRQ_MAC_RX;
+               break;
+
+       case CH_EMAC_TX:
+               ret_irq = IRQ_MAC_TX;
+               break;
+
+       case CH_UART1_RX:
+               ret_irq = IRQ_UART1_RX;
+               break;
+
+       case CH_UART1_TX:
+               ret_irq = IRQ_UART1_TX;
+               break;
+
+       case CH_SPORT0_RX:
+               ret_irq = IRQ_SPORT0_RX;
+               break;
+
+       case CH_SPORT0_TX:
+               ret_irq = IRQ_SPORT0_TX;
+               break;
+
+       case CH_SPORT1_RX:
+               ret_irq = IRQ_SPORT1_RX;
+               break;
+
+       case CH_SPORT1_TX:
+               ret_irq = IRQ_SPORT1_TX;
+               break;
+
+       case CH_SPI:
+               ret_irq = IRQ_SPI;
+               break;
+
+       case CH_UART0_RX:
+               ret_irq = IRQ_UART0_RX;
+               break;
+
+       case CH_UART0_TX:
+               ret_irq = IRQ_UART0_TX;
+               break;
+
+       case CH_MEM_STREAM0_SRC:
+       case CH_MEM_STREAM0_DEST:
+               ret_irq = IRQ_MEM_DMA0;
+               break;
+
+       case CH_MEM_STREAM1_SRC:
+       case CH_MEM_STREAM1_DEST:
+               ret_irq = IRQ_MEM_DMA1;
+               break;
+       }
+       return ret_irq;
+}
diff --git a/arch/blackfin/mach-bf527/head.S b/arch/blackfin/mach-bf527/head.S
new file mode 100644 (file)
index 0000000..cdb00a0
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * File:         arch/blackfin/mach-bf527/head.S
+ * Based on:     arch/blackfin/mach-bf533/head.S
+ * Author:       Jeff Dionne <jeff@uclinux.org> COPYRIGHT 1998 D. Jeff Dionne
+ *
+ * Created:      1998
+ * Description:  Startup code for Blackfin BF537
+ *
+ * Modified:
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/blackfin.h>
+#include <asm/trace.h>
+
+#if CONFIG_BFIN_KERNEL_CLOCK
+#include <asm/mach-common/clocks.h>
+#include <asm/mach/mem_init.h>
+#endif
+
+.global __rambase
+.global __ramstart
+.global __ramend
+.extern ___bss_stop
+.extern ___bss_start
+.extern _bf53x_relocate_l1_mem
+
+#define INITIAL_STACK  0xFFB01000
+
+__INIT
+
+ENTRY(__start)
+       /* R0: argument of command line string, passed from uboot, save it */
+       R7 = R0;
+       /* Enable Cycle Counter and Nesting Of Interrupts */
+#ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES
+       R0 = SYSCFG_SNEN;
+#else
+       R0 = SYSCFG_SNEN | SYSCFG_CCEN;
+#endif
+       SYSCFG = R0;
+       R0 = 0;
+
+       /* Clear Out All the data and pointer Registers */
+       R1 = R0;
+       R2 = R0;
+       R3 = R0;
+       R4 = R0;
+       R5 = R0;
+       R6 = R0;
+
+       P0 = R0;
+       P1 = R0;
+       P2 = R0;
+       P3 = R0;
+       P4 = R0;
+       P5 = R0;
+
+       LC0 = r0;
+       LC1 = r0;
+       L0 = r0;
+       L1 = r0;
+       L2 = r0;
+       L3 = r0;
+
+       /* Clear Out All the DAG Registers */
+       B0 = r0;
+       B1 = r0;
+       B2 = r0;
+       B3 = r0;
+
+       I0 = r0;
+       I1 = r0;
+       I2 = r0;
+       I3 = r0;
+
+       M0 = r0;
+       M1 = r0;
+       M2 = r0;
+       M3 = r0;
+
+       trace_buffer_init(p0,r0);
+       P0 = R1;
+       R0 = R1;
+
+       /* Turn off the icache */
+       p0.l = LO(IMEM_CONTROL);
+       p0.h = HI(IMEM_CONTROL);
+       R1 = [p0];
+       R0 = ~ENICPLB;
+       R0 = R0 & R1;
+
+       /* Anomaly 05000125 */
+#if ANOMALY_05000125
+       CLI R2;
+       SSYNC;
+#endif
+       [p0] = R0;
+       SSYNC;
+#if ANOMALY_05000125
+       STI R2;
+#endif
+
+       /* Turn off the dcache */
+       p0.l = LO(DMEM_CONTROL);
+       p0.h = HI(DMEM_CONTROL);
+       R1 = [p0];
+       R0 = ~ENDCPLB;
+       R0 = R0 & R1;
+
+       /* Anomaly 05000125 */
+#if ANOMALY_05000125
+       CLI R2;
+       SSYNC;
+#endif
+       [p0] = R0;
+       SSYNC;
+#if ANOMALY_05000125
+       STI R2;
+#endif
+
+
+#if defined(CONFIG_BF527)
+       p0.h = hi(EMAC_SYSTAT);
+       p0.l = lo(EMAC_SYSTAT);
+       R0.h = 0xFFFF; /* Clear EMAC Interrupt Status bits */
+       R0.l = 0xFFFF;
+       [P0] = R0;
+       SSYNC;
+#endif
+
+       /* Initialise UART - when booting from u-boot, the UART is not disabled
+        * so if we dont initalize here, our serial console gets hosed */
+       p0.h = hi(UART1_LCR);
+       p0.l = lo(UART1_LCR);
+       r0 = 0x0(Z);
+       w[p0] = r0.L;   /* To enable DLL writes */
+       ssync;
+
+       p0.h = hi(UART1_DLL);
+       p0.l = lo(UART1_DLL);
+       r0 = 0x0(Z);
+       w[p0] = r0.L;
+       ssync;
+
+       p0.h = hi(UART1_DLH);
+       p0.l = lo(UART1_DLH);
+       r0 = 0x00(Z);
+       w[p0] = r0.L;
+       ssync;
+
+       p0.h = hi(UART1_GCTL);
+       p0.l = lo(UART1_GCTL);
+       r0 = 0x0(Z);
+       w[p0] = r0.L;   /* To enable UART clock */
+       ssync;
+
+       /* Initialize stack pointer */
+       sp.l = lo(INITIAL_STACK);
+       sp.h = hi(INITIAL_STACK);
+       fp = sp;
+       usp = sp;
+
+#ifdef CONFIG_EARLY_PRINTK
+       SP += -12;
+       call _init_early_exception_vectors;
+       SP += 12;
+#endif
+
+       /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
+       call _bf53x_relocate_l1_mem;
+#if CONFIG_BFIN_KERNEL_CLOCK
+       call _start_dma_code;
+#endif
+
+       /* Code for initializing Async memory banks */
+
+       p2.h = hi(EBIU_AMBCTL1);
+       p2.l = lo(EBIU_AMBCTL1);
+       r0.h = hi(AMBCTL1VAL);
+       r0.l = lo(AMBCTL1VAL);
+       [p2] = r0;
+       ssync;
+
+       p2.h = hi(EBIU_AMBCTL0);
+       p2.l = lo(EBIU_AMBCTL0);
+       r0.h = hi(AMBCTL0VAL);
+       r0.l = lo(AMBCTL0VAL);
+       [p2] = r0;
+       ssync;
+
+       p2.h = hi(EBIU_AMGCTL);
+       p2.l = lo(EBIU_AMGCTL);
+       r0 = AMGCTLVAL;
+       w[p2] = r0;
+       ssync;
+
+       /* This section keeps the processor in supervisor mode
+        * during kernel boot.  Switches to user mode at end of boot.
+        * See page 3-9 of Hardware Reference manual for documentation.
+        */
+
+       /* EVT15 = _real_start */
+
+       p0.l = lo(EVT15);
+       p0.h = hi(EVT15);
+       p1.l = _real_start;
+       p1.h = _real_start;
+       [p0] = p1;
+       csync;
+
+       p0.l = lo(IMASK);
+       p0.h = hi(IMASK);
+       p1.l = IMASK_IVG15;
+       p1.h = 0x0;
+       [p0] = p1;
+       csync;
+
+       raise 15;
+       p0.l = .LWAIT_HERE;
+       p0.h = .LWAIT_HERE;
+       reti = p0;
+#if ANOMALY_05000281
+       nop; nop; nop;
+#endif
+       rti;
+
+.LWAIT_HERE:
+       jump .LWAIT_HERE;
+ENDPROC(__start)
+
+ENTRY(_real_start)
+       [ -- sp ] = reti;
+       p0.l = lo(WDOG_CTL);
+       p0.h = hi(WDOG_CTL);
+       r0 = 0xAD6(z);
+       w[p0] = r0;     /* watchdog off for now */
+       ssync;
+
+       /* Code update for BSS size == 0
+        * Zero out the bss region.
+        */
+
+       p1.l = ___bss_start;
+       p1.h = ___bss_start;
+       p2.l = ___bss_stop;
+       p2.h = ___bss_stop;
+       r0 = 0;
+       p2 -= p1;
+       lsetup (.L_clear_bss, .L_clear_bss) lc0 = p2;
+.L_clear_bss:
+       B[p1++] = r0;
+
+       /* In case there is a NULL pointer reference
+        * Zero out region before stext
+        */
+
+       p1.l = 0x0;
+       p1.h = 0x0;
+       r0.l = __stext;
+       r0.h = __stext;
+       r0 = r0 >> 1;
+       p2 = r0;
+       r0 = 0;
+       lsetup (.L_clear_zero, .L_clear_zero) lc0 = p2;
+.L_clear_zero:
+       W[p1++] = r0;
+
+       /* pass the uboot arguments to the global value command line */
+       R0 = R7;
+       call _cmdline_init;
+
+       p1.l = __rambase;
+       p1.h = __rambase;
+       r0.l = __sdata;
+       r0.h = __sdata;
+       [p1] = r0;
+
+       p1.l = __ramstart;
+       p1.h = __ramstart;
+       p3.l = ___bss_stop;
+       p3.h = ___bss_stop;
+
+       r1 = p3;
+       [p1] = r1;
+
+       /*
+        * load the current thread pointer and stack
+        */
+       r1.l = _init_thread_union;
+       r1.h = _init_thread_union;
+
+       r2.l = 0x2000;
+       r2.h = 0x0000;
+       r1 = r1 + r2;
+       sp = r1;
+       usp = sp;
+       fp = sp;
+       jump.l _start_kernel;
+ENDPROC(_real_start)
+
+__FINIT
+
+.section .l1.text
+#if CONFIG_BFIN_KERNEL_CLOCK
+ENTRY(_start_dma_code)
+
+       /* Enable PHY CLK buffer output */
+       p0.h = hi(VR_CTL);
+       p0.l = lo(VR_CTL);
+       r0.l = w[p0];
+       bitset(r0, 14);
+       w[p0] = r0.l;
+       ssync;
+
+       p0.h = hi(SIC_IWR0);
+       p0.l = lo(SIC_IWR0);
+       r0.l = 0x1;
+       r0.h = 0x0;
+       [p0] = r0;
+       SSYNC;
+
+       /*
+        *  Set PLL_CTL
+        *   - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
+        *   - [8]     = BYPASS    : BYPASS the PLL, run CLKIN into CCLK/SCLK
+        *   - [7]     = output delay (add 200ps of delay to mem signals)
+        *   - [6]     = input delay (add 200ps of input delay to mem signals)
+        *   - [5]     = PDWN      : 1=All Clocks off
+        *   - [3]     = STOPCK    : 1=Core Clock off
+        *   - [1]     = PLL_OFF   : 1=Disable Power to PLL
+        *   - [0]     = DF        : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
+        *   all other bits set to zero
+        */
+
+       p0.h = hi(PLL_LOCKCNT);
+       p0.l = lo(PLL_LOCKCNT);
+       r0 = 0x300(Z);
+       w[p0] = r0.l;
+       ssync;
+
+       P2.H = hi(EBIU_SDGCTL);
+       P2.L = lo(EBIU_SDGCTL);
+       R0 = [P2];
+       BITSET (R0, 24);
+       [P2] = R0;
+       SSYNC;
+
+       r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
+       r0 = r0 << 9;                    /* Shift it over,                  */
+       r1 = CLKIN_HALF;                 /* Do we need to divide CLKIN by 2?*/
+       r0 = r1 | r0;
+       r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
+       r1 = r1 << 8;                    /* Shift it over                   */
+       r0 = r1 | r0;                    /* add them all together           */
+
+       p0.h = hi(PLL_CTL);
+       p0.l = lo(PLL_CTL);              /* Load the address                */
+       cli r2;                          /* Disable interrupts              */
+       ssync;
+       w[p0] = r0.l;                    /* Set the value                   */
+       idle;                            /* Wait for the PLL to stablize    */
+       sti r2;                          /* Enable interrupts               */
+
+.Lcheck_again:
+       p0.h = hi(PLL_STAT);
+       p0.l = lo(PLL_STAT);
+       R0 = W[P0](Z);
+       CC = BITTST(R0,5);
+       if ! CC jump .Lcheck_again;
+
+       /* Configure SCLK & CCLK Dividers */
+       r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+       p0.h = hi(PLL_DIV);
+       p0.l = lo(PLL_DIV);
+       w[p0] = r0.l;
+       ssync;
+
+       p0.l = lo(EBIU_SDRRC);
+       p0.h = hi(EBIU_SDRRC);
+       r0 = mem_SDRRC;
+       w[p0] = r0.l;
+       ssync;
+
+       p0.l = LO(EBIU_SDBCTL);
+       p0.h = HI(EBIU_SDBCTL);     /* SDRAM Memory Bank Control Register */
+       r0 = mem_SDBCTL;
+       w[p0] = r0.l;
+       ssync;
+
+       P2.H = hi(EBIU_SDGCTL);
+       P2.L = lo(EBIU_SDGCTL);
+       R0 = [P2];
+       BITCLR (R0, 24);
+       p0.h = hi(EBIU_SDSTAT);
+       p0.l = lo(EBIU_SDSTAT);
+       r2.l = w[p0];
+       cc = bittst(r2,3);
+       if !cc jump .Lskip;
+       NOP;
+       BITSET (R0, 23);
+.Lskip:
+       [P2] = R0;
+       SSYNC;
+
+       R0.L = lo(mem_SDGCTL);
+       R0.H = hi(mem_SDGCTL);
+       R1 = [p2];
+       R1 = R1 | R0;
+       [P2] = R1;
+       SSYNC;
+
+       p0.h = hi(SIC_IWR0);
+       p0.l = lo(SIC_IWR0);
+       r0.l = lo(IWR_ENABLE_ALL);
+       r0.h = hi(IWR_ENABLE_ALL);
+       [p0] = r0;
+       SSYNC;
+
+       RTS;
+ENDPROC(_start_dma_code)
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+.data
+
+/*
+ * Set up the usable of RAM stuff. Size of RAM is determined then
+ * an initial stack set up at the end.
+ */
+
+.align 4
+__rambase:
+.long   0
+__ramstart:
+.long   0
+__ramend:
+.long   0
diff --git a/arch/blackfin/mach-bf527/ints-priority.c b/arch/blackfin/mach-bf527/ints-priority.c
new file mode 100644 (file)
index 0000000..1fa3897
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * File:         arch/blackfin/mach-bf537/ints-priority.c
+ * Based on:     arch/blackfin/mach-bf533/ints-priority.c
+ * Author:       Michael Hennerich (michael.hennerich@analog.com)
+ *
+ * Created:
+ * Description:  Set up the interrupt priorities
+ *
+ * Modified:
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <asm/blackfin.h>
+
+void program_IAR(void)
+{
+       /* Program the IAR0 Register with the configured priority */
+       bfin_write_SIC_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
+                       ((CONFIG_IRQ_DMA0_ERROR - 7) << IRQ_DMA0_ERROR_POS) |
+                       ((CONFIG_IRQ_DMAR0_BLK - 7) << IRQ_DMAR0_BLK_POS) |
+                       ((CONFIG_IRQ_DMAR1_BLK - 7) << IRQ_DMAR1_BLK_POS) |
+                       ((CONFIG_IRQ_DMAR0_OVR - 7) << IRQ_DMAR0_OVR_POS) |
+                       ((CONFIG_IRQ_DMAR1_OVR - 7) << IRQ_DMAR1_OVR_POS) |
+                       ((CONFIG_IRQ_PPI_ERROR - 7) << IRQ_PPI_ERROR_POS) |
+                       ((CONFIG_IRQ_MAC_ERROR - 7) << IRQ_MAC_ERROR_POS));
+
+
+       bfin_write_SIC_IAR1(((CONFIG_IRQ_SPORT0_ERROR - 7) << IRQ_SPORT0_ERROR_POS) |
+                       ((CONFIG_IRQ_SPORT1_ERROR - 7) << IRQ_SPORT1_ERROR_POS) |
+                       ((CONFIG_IRQ_UART0_ERROR - 7) << IRQ_UART0_ERROR_POS) |
+                       ((CONFIG_IRQ_UART1_ERROR - 7) << IRQ_UART1_ERROR_POS) |
+                       ((CONFIG_IRQ_RTC - 7) << IRQ_RTC_POS) |
+                       ((CONFIG_IRQ_PPI - 7) << IRQ_PPI_POS));
+
+       bfin_write_SIC_IAR2(((CONFIG_IRQ_SPORT0_RX - 7) << IRQ_SPORT0_RX_POS) |
+                       ((CONFIG_IRQ_SPORT0_TX - 7) << IRQ_SPORT0_TX_POS) |
+                       ((CONFIG_IRQ_SPORT1_RX - 7) << IRQ_SPORT1_RX_POS) |
+                       ((CONFIG_IRQ_SPORT1_TX - 7) << IRQ_SPORT1_TX_POS) |
+                       ((CONFIG_IRQ_TWI - 7) << IRQ_TWI_POS) |
+                       ((CONFIG_IRQ_SPI - 7) << IRQ_SPI_POS) |
+                       ((CONFIG_IRQ_UART0_RX - 7) << IRQ_UART0_RX_POS) |
+                       ((CONFIG_IRQ_UART0_TX - 7) << IRQ_UART0_TX_POS));
+
+       bfin_write_SIC_IAR3(((CONFIG_IRQ_UART1_RX - 7) << IRQ_UART1_RX_POS) |
+                       ((CONFIG_IRQ_UART1_TX - 7) << IRQ_UART1_TX_POS) |
+                       ((CONFIG_IRQ_OPTSEC - 7) << IRQ_OPTSEC_POS) |
+                       ((CONFIG_IRQ_CNT - 7) << IRQ_CNT_POS) |
+                       ((CONFIG_IRQ_MAC_RX - 7) << IRQ_MAC_RX_POS) |
+                       ((CONFIG_IRQ_PORTH_INTA - 7) << IRQ_PORTH_INTA_POS) |
+                       ((CONFIG_IRQ_MAC_TX - 7) << IRQ_MAC_TX_POS) |
+                       ((CONFIG_IRQ_PORTH_INTB - 7) << IRQ_PORTH_INTB_POS));
+
+       bfin_write_SIC_IAR4(((CONFIG_IRQ_TMR0 - 7) << IRQ_TMR0_POS) |
+                       ((CONFIG_IRQ_TMR1 - 7) << IRQ_TMR1_POS) |
+                       ((CONFIG_IRQ_TMR2 - 7) << IRQ_TMR2_POS) |
+                       ((CONFIG_IRQ_TMR3 - 7) << IRQ_TMR3_POS) |
+                       ((CONFIG_IRQ_TMR4 - 7) << IRQ_TMR4_POS) |
+                       ((CONFIG_IRQ_TMR5 - 7) << IRQ_TMR5_POS) |
+                       ((CONFIG_IRQ_TMR6 - 7) << IRQ_TMR6_POS) |
+                       ((CONFIG_IRQ_TMR7 - 7) << IRQ_TMR7_POS));
+
+       bfin_write_SIC_IAR5(((CONFIG_IRQ_PORTG_INTA - 7) << IRQ_PORTG_INTA_POS) |
+                       ((CONFIG_IRQ_PORTG_INTB - 7) << IRQ_PORTG_INTB_POS) |
+                       ((CONFIG_IRQ_MEM_DMA0 - 7) << IRQ_MEM_DMA0_POS) |
+                       ((CONFIG_IRQ_MEM_DMA1 - 7) << IRQ_MEM_DMA1_POS) |
+                       ((CONFIG_IRQ_WATCH - 7) << IRQ_WATCH_POS) |
+                       ((CONFIG_IRQ_PORTF_INTA - 7) << IRQ_PORTF_INTA_POS) |
+                       ((CONFIG_IRQ_PORTF_INTB - 7) << IRQ_PORTF_INTB_POS) |
+                       ((CONFIG_IRQ_SPI_ERROR - 7) << IRQ_SPI_ERROR_POS));
+
+       bfin_write_SIC_IAR6(((CONFIG_IRQ_NFC_ERROR - 7) << IRQ_NFC_ERROR_POS) |
+                       ((CONFIG_IRQ_HDMA_ERROR - 7) << IRQ_HDMA_ERROR_POS) |
+                       ((CONFIG_IRQ_HDMA - 7) << IRQ_HDMA_POS) |
+                       ((CONFIG_IRQ_USB_EINT - 7) << IRQ_USB_EINT_POS) |
+                       ((CONFIG_IRQ_USB_INT0 - 7) << IRQ_USB_INT0_POS) |
+                       ((CONFIG_IRQ_USB_INT1 - 7) << IRQ_USB_INT1_POS) |
+                       ((CONFIG_IRQ_USB_INT2 - 7) << IRQ_USB_INT2_POS) |
+                       ((CONFIG_IRQ_USB_DMA - 7) << IRQ_USB_DMA_POS));
+
+       SSYNC();
+}
index a57b52d..1c5a86a 100644 (file)
@@ -42,7 +42,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "Bluetechnix CM BF533";
+const char bfin_board_name[] = "Bluetechnix CM BF533";
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* all SPI peripherals info goes here */
index 5c1e35d..34b6392 100644 (file)
@@ -43,7 +43,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "ADDS-BF533-EZKIT";
+const char bfin_board_name[] = "ADDS-BF533-EZKIT";
 
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 static struct platform_device rtc_device = {
index 9bc1f0d..310b777 100644 (file)
@@ -35,7 +35,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "UNKNOWN BOARD";
+const char bfin_board_name[] = "UNKNOWN BOARD";
 
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 static struct platform_device rtc_device = {
index 8975e06..f84be4e 100644 (file)
@@ -46,7 +46,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "ADDS-BF533-STAMP";
+const char bfin_board_name[] = "ADDS-BF533-STAMP";
 
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 static struct platform_device rtc_device = {
index 44dea05..52e2320 100644 (file)
@@ -43,7 +43,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "Bluetechnix CM BF537";
+const char bfin_board_name[] = "Bluetechnix CM BF537";
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* all SPI peripherals info goes here */
index 6668c8e..255da7a 100644 (file)
@@ -49,7 +49,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "GENERIC Board";
+const char bfin_board_name[] = "GENERIC Board";
 
 /*
  *  Driver needs to know address, irq and flag pin.
index f83a254..87b8089 100644 (file)
@@ -47,7 +47,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "PNAV-1.0";
+const char bfin_board_name[] = "PNAV-1.0";
 
 /*
  *  Driver needs to know address, irq and flag pin.
index f42ba3a..cc41f6c 100644 (file)
@@ -49,7 +49,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "ADDS-BF537-STAMP";
+const char bfin_board_name[] = "ADDS-BF537-STAMP";
 
 /*
  *  Driver needs to know address, irq and flag pin.
index 046e6d8..6b6490e 100644 (file)
@@ -49,7 +49,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "ADSP-BF548-EZKIT";
+const char bfin_board_name[] = "ADSP-BF548-EZKIT";
 
 /*
  *  Driver needs to know address, irq and flag pin.
@@ -560,7 +560,7 @@ static struct platform_device *ezkit_devices[] __initdata = {
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
        &bf54x_spi_master0,
-/*     &bf54x_spi_master1,*/
+       &bf54x_spi_master1,
 #endif
 
 #if defined(CONFIG_KEYBOARD_BFIN) || defined(CONFIG_KEYBOARD_BFIN_MODULE)
index a818411..957bf13 100644 (file)
@@ -64,6 +64,7 @@
        (struct dma_register *) MDMA_D3_NEXT_DESC_PTR,
        (struct dma_register *) MDMA_S3_NEXT_DESC_PTR,
 };
+EXPORT_SYMBOL(base_addr);
 
 int channel2irq(unsigned int channel)
 {
index cd827a1..97aeb43 100644 (file)
@@ -42,7 +42,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "Bluetechnix CM BF561";
+const char bfin_board_name[] = "Bluetechnix CM BF561";
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* all SPI peripherals info goes here */
index 57e14ed..059d516 100644 (file)
@@ -39,7 +39,7 @@
 /*
  * Name the Board for the /proc/cpuinfo
  */
-char *bfin_board_name = "ADDS-BF561-EZKIT";
+const char bfin_board_name[] = "ADDS-BF561-EZKIT";
 
 #define ISP1761_BASE       0x2C0F0000
 #define ISP1761_IRQ        IRQ_PF10
index 4dfea5d..46816be 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 
-char *bfin_board_name = "UNKNOWN BOARD";
+const char bfin_board_name[] = "UNKNOWN BOARD";
 
 /*
  *  Driver needs to know address, irq and flag pin.
index c442eb2..4a17c6d 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 
-char *bfin_board_name = "Tepla-BF561";
+const char bfin_board_name[] = "Tepla-BF561";
 
 /*
  *  Driver needs to know address, irq and flag pin.
index 2db3546..c2f05fa 100644 (file)
  * -
  */
 
-unsigned long irq_flags = 0;
+/* Initialize this to an actual value to force it into the .data
+ * section so that we know it is properly initialized at entry into
+ * the kernel but before bss is initialized to zero (which is where
+ * it would live otherwise).  The 0x1f magic represents the IRQs we
+ * cannot actually mask out in hardware.
+ */
+unsigned long irq_flags = 0x1f;
 
 /* The number of spurious interrupts */
 atomic_t num_spurious;
index d3b7672..2d2b635 100644 (file)
  * -
  */
 
-unsigned long irq_flags = 0;
+/* Initialize this to an actual value to force it into the .data
+ * section so that we know it is properly initialized at entry into
+ * the kernel but before bss is initialized to zero (which is where
+ * it would live otherwise).  The 0x1f magic represents the IRQs we
+ * cannot actually mask out in hardware.
+ */
+unsigned long irq_flags = 0x1f;
 
 /* The number of spurious interrupts */
 atomic_t num_spurious;
@@ -92,10 +98,15 @@ static void __init search_IAR(void)
 
                for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
                        int iar_shift = (irqn & 7) * 4;
-                       if (ivg ==
+                               if (ivg ==
                            (0xf &
+#ifndef CONFIG_BF52x
                             bfin_read32((unsigned long *)SIC_IAR0 +
                                         (irqn >> 3)) >> iar_shift)) {
+#else
+                            bfin_read32((unsigned long *)SIC_IAR0 +
+                                        ((irqn%32) >> 3) + ((irqn / 32) * 16)) >> iar_shift)) {
+#endif
                                ivg_table[irq_pos].irqno = IVG7 + irqn;
                                ivg_table[irq_pos].isrflag = 1 << (irqn % 32);
                                ivg7_13[ivg].istop++;
@@ -140,7 +151,7 @@ static void bfin_core_unmask_irq(unsigned int irq)
 
 static void bfin_internal_mask_irq(unsigned int irq)
 {
-#ifndef CONFIG_BF54x
+#ifdef CONFIG_BF53x
        bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
                             ~(1 << (irq - (IRQ_CORETMR + 1))));
 #else
@@ -155,7 +166,7 @@ static void bfin_internal_mask_irq(unsigned int irq)
 
 static void bfin_internal_unmask_irq(unsigned int irq)
 {
-#ifndef CONFIG_BF54x
+#ifdef CONFIG_BF53x
        bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
                             (1 << (irq - (IRQ_CORETMR + 1))));
 #else
@@ -750,13 +761,15 @@ int __init init_arch_irq(void)
        int irq;
        unsigned long ilat = 0;
        /*  Disable all the peripheral intrs  - page 4-29 HW Ref manual */
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
        bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
        bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
-       bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
        bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
        bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
+#ifdef CONFIG_BF54x
+       bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
        bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
+#endif
 #else
        bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
        bfin_write_SIC_IWR(IWR_ENABLE_ALL);
@@ -787,7 +800,7 @@ int __init init_arch_irq(void)
 
                        switch (irq) {
 #ifdef CONFIG_IRQCHIP_DEMUX_GPIO
-#ifndef CONFIG_BF54x
+#if defined(CONFIG_BF53x)
                        case IRQ_PROG_INTA:
                                set_irq_chained_handler(irq,
                                                        bfin_demux_gpio_irq);
@@ -798,7 +811,7 @@ int __init init_arch_irq(void)
                                                        bfin_demux_gpio_irq);
                                break;
 #endif
-#else
+#elif defined(CONFIG_BF54x)
                        case IRQ_PINT0:
                                set_irq_chained_handler(irq,
                                                        bfin_demux_gpio_irq);
@@ -815,7 +828,20 @@ int __init init_arch_irq(void)
                                set_irq_chained_handler(irq,
                                                        bfin_demux_gpio_irq);
                                break;
-#endif                         /*CONFIG_BF54x */
+#elif defined(CONFIG_BF52x)
+                       case IRQ_PORTF_INTA:
+                               set_irq_chained_handler(irq,
+                                                       bfin_demux_gpio_irq);
+                               break;
+                       case IRQ_PORTG_INTA:
+                               set_irq_chained_handler(irq,
+                                                       bfin_demux_gpio_irq);
+                               break;
+                       case IRQ_PORTH_INTA:
+                               set_irq_chained_handler(irq,
+                                                       bfin_demux_gpio_irq);
+                               break;
+#endif
 #endif
                        default:
                                set_irq_handler(irq, handle_simple_irq);
@@ -880,14 +906,15 @@ void do_irq(int vec, struct pt_regs *fp)
        } else {
                struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
                struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
                unsigned long sic_status[3];
 
                SSYNC();
-               sic_status[0] = bfin_read_SIC_ISR(0) & bfin_read_SIC_IMASK(0);
-               sic_status[1] = bfin_read_SIC_ISR(1) & bfin_read_SIC_IMASK(1);
-               sic_status[2] = bfin_read_SIC_ISR(2) & bfin_read_SIC_IMASK(2);
-
+               sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
+               sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
+#ifdef CONFIG_BF54x
+               sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
+#endif
                for (;; ivg++) {
                        if (ivg >= ivg_stop) {
                                atomic_inc(&num_spurious);
index f6e44fc..5bed8be 100644 (file)
@@ -227,28 +227,40 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER
          If in doubt, say "Y".
 
 config PARAVIRT
-       bool "Paravirtualization support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       bool
        depends on !(X86_VISWS || X86_VOYAGER)
        help
-         Paravirtualization is a way of running multiple instances of
-         Linux on the same machine, under a hypervisor.  This option
-         changes the kernel so it can modify itself when it is run
-         under a hypervisor, improving performance significantly.
-         However, when run without a hypervisor the kernel is
-         theoretically slower.  If in doubt, say N.
+         This changes the kernel so it can modify itself when it is run
+         under a hypervisor, potentially improving performance significantly
+         over full virtualization.  However, when run without a hypervisor
+         the kernel is theoretically slower and slightly larger.
+
+menuconfig PARAVIRT_GUEST
+       bool "Paravirtualized guest support"
+       help
+         Say Y here to get to see options related to running Linux under
+         various hypervisors.  This option alone does not add any kernel code.
+
+         If you say N, all options in this submenu will be skipped and disabled.
+
+if PARAVIRT_GUEST
 
 source "arch/x86/xen/Kconfig"
 
 config VMI
-       bool "VMI Paravirt-ops support"
-       depends on PARAVIRT
+       bool "VMI Guest support"
+       select PARAVIRT
+       depends on !(X86_VISWS || X86_VOYAGER)
        help
          VMI provides a paravirtualized interface to the VMware ESX server
          (it could be used by other hypervisors in theory too, but is not
          at the moment), by linking the kernel to a GPL-ed ROM module
          provided by the hypervisor.
 
+source "arch/x86/lguest/Kconfig"
+
+endif
+
 config ACPI_SRAT
        bool
        default y
index b88e47c..b81cb64 100644 (file)
@@ -99,6 +99,9 @@ core-$(CONFIG_X86_ES7000)     := arch/x86/mach-es7000/
 # Xen paravirtualization support
 core-$(CONFIG_XEN)             += arch/x86/xen/
 
+# lguest paravirtualization support
+core-$(CONFIG_LGUEST_GUEST)    += arch/x86/lguest/
+
 # default subarch .h files
 mflags-y += -Iinclude/asm-x86/mach-default
 
index 3c95f41..bc859a3 100644 (file)
@@ -246,7 +246,7 @@ static int reserve_sba_gart = 1;
 static SBA_INLINE void sba_mark_invalid(struct ioc *, dma_addr_t, size_t);
 static SBA_INLINE void sba_free_range(struct ioc *, dma_addr_t, size_t);
 
-#define sba_sg_address(sg)     (page_address((sg)->page) + (sg)->offset)
+#define sba_sg_address(sg)     sg_virt((sg))
 
 #ifdef FULL_VALID_PDIR
 static u64 prefetch_spill_page;
index a3a558a..6ef9b52 100644 (file)
@@ -131,7 +131,7 @@ simscsi_sg_readwrite (struct scsi_cmnd *sc, int mode, unsigned long offset)
        stat.fd = desc[sc->device->id];
 
        scsi_for_each_sg(sc, sl, scsi_sg_count(sc), i) {
-               req.addr = __pa(page_address(sl->page) + sl->offset);
+               req.addr = __pa(sg_virt(sl));
                req.len  = sl->length;
                if (DBG)
                        printk("simscsi_sg_%s @ %lx (off %lx) use_sg=%d len=%d\n",
@@ -212,7 +212,7 @@ static void simscsi_fillresult(struct scsi_cmnd *sc, char *buf, unsigned len)
                if (!len)
                        break;
                thislen = min(len, slp->length);
-               memcpy(page_address(slp->page) + slp->offset, buf, thislen);
+               memcpy(sg_virt(slp), buf, thislen);
                len -= thislen;
        }
 }
index 8e4894b..3f7ea13 100644 (file)
@@ -1090,7 +1090,8 @@ efi_memmap_init(unsigned long *s, unsigned long *e)
 
 void
 efi_initialize_iomem_resources(struct resource *code_resource,
-                              struct resource *data_resource)
+                              struct resource *data_resource,
+                              struct resource *bss_resource)
 {
        struct resource *res;
        void *efi_map_start, *efi_map_end, *p;
@@ -1171,6 +1172,7 @@ efi_initialize_iomem_resources(struct resource *code_resource,
                         */
                        insert_resource(res, code_resource);
                        insert_resource(res, data_resource);
+                       insert_resource(res, bss_resource);
 #ifdef CONFIG_KEXEC
                         insert_resource(res, &efi_memmap_res);
                         insert_resource(res, &boot_param_res);
index cbf67f1..ae6c3c0 100644 (file)
@@ -90,7 +90,12 @@ static struct resource code_resource = {
        .name   = "Kernel code",
        .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
 };
-extern char _text[], _end[], _etext[];
+
+static struct resource bss_resource = {
+       .name   = "Kernel bss",
+       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+extern char _text[], _end[], _etext[], _edata[], _bss[];
 
 unsigned long ia64_max_cacheline_size;
 
@@ -200,8 +205,11 @@ static int __init register_memory(void)
        code_resource.start = ia64_tpa(_text);
        code_resource.end   = ia64_tpa(_etext) - 1;
        data_resource.start = ia64_tpa(_etext);
-       data_resource.end   = ia64_tpa(_end) - 1;
-       efi_initialize_iomem_resources(&code_resource, &data_resource);
+       data_resource.end   = ia64_tpa(_edata) - 1;
+       bss_resource.start  = ia64_tpa(_bss);
+       bss_resource.end    = ia64_tpa(_end) - 1;
+       efi_initialize_iomem_resources(&code_resource, &data_resource,
+                       &bss_resource);
 
        return 0;
 }
index ecd8a52..511db2f 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/sn/pcidev.h>
 #include <asm/sn/sn_sal.h>
 
-#define SG_ENT_VIRT_ADDRESS(sg)        (page_address((sg)->page) + (sg)->offset)
+#define SG_ENT_VIRT_ADDRESS(sg)        (sg_virt((sg)))
 #define SG_ENT_PHYS_ADDRESS(SG)        virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
 
 /**
index 9d4e4b5..ef490e1 100644 (file)
@@ -121,7 +121,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        int i;
 
        for (i = 0; i < nents; sg++, i++) {
-               sg->dma_address = page_to_phys(sg->page) + sg->offset;
+               sg->dma_address = sg_phys(sg);
                dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
        }
        return nents;
index f52c627..f4b582c 100644 (file)
@@ -451,6 +451,12 @@ config MOD5272
        help
          Support for the Netburner MOD-5272 board.
 
+config SAVANTrosie1
+       bool "Savant Rosie1 board support"
+       depends on M523x
+       help
+         Support for the Savant Rosie1 board.
+
 config ROMFS_FROM_ROM
        bool "ROMFS image not RAM resident"
        depends on (NETtel || SNAPGEAR)
@@ -492,7 +498,12 @@ config SNEHA
         bool
        default y
        depends on CPU16B
-       
+
+config SAVANT
+       bool
+       default y
+       depends on SAVANTrosie1
+
 config AVNET
        bool
        default y
index 92227aa..30aa255 100644 (file)
@@ -48,6 +48,7 @@ board-$(CONFIG_SNEHA)                 := SNEHA
 board-$(CONFIG_M5208EVB)       := M5208EVB
 board-$(CONFIG_MOD5272)                := MOD5272
 board-$(CONFIG_AVNET)           := AVNET
+board-$(CONFIG_SAVANT)         := SAVANT
 BOARD := $(board-y)
 
 model-$(CONFIG_RAMKERNEL)      := ram
@@ -117,4 +118,4 @@ core-y      += arch/m68knommu/kernel/ \
 libs-y += arch/m68knommu/lib/
 
 archclean:
-       $(Q)$(MAKE) $(clean)=arch/m68knommu/boot
+
index 3891de0..5a0ecaa 100644 (file)
@@ -1,41 +1,48 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17
-# Tue Jun 27 12:57:06 2006
+# Linux kernel version: 2.6.23
+# Thu Oct 18 13:17:38 2007
 #
 CONFIG_M68K=y
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
+CONFIG_ZONE_DMA=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_TIME_LOW_RES=y
+CONFIG_NO_IOPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 # CONFIG_SYSVIPC is not set
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SYSFS_DEPRECATED is not set
 # CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
+# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
@@ -44,20 +51,25 @@ CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# Block layer
-#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -99,6 +111,7 @@ CONFIG_CLOCK_DIV=1
 #
 # Platform
 #
+# CONFIG_UC5272 is not set
 CONFIG_M5272C3=y
 # CONFIG_COBRA5272 is not set
 # CONFIG_CANCam is not set
@@ -107,7 +120,6 @@ CONFIG_M5272C3=y
 # CONFIG_CPU16B is not set
 # CONFIG_MOD5272 is not set
 CONFIG_FREESCALE=y
-# CONFIG_LARGE_ALLOCS is not set
 CONFIG_4KSTACKS=y
 
 #
@@ -121,6 +133,11 @@ CONFIG_RAMAUTOBIT=y
 # CONFIG_RAM8BIT is not set
 # CONFIG_RAM16BIT is not set
 # CONFIG_RAM32BIT is not set
+
+#
+# ROM configuration
+#
+# CONFIG_ROM is not set
 CONFIG_RAMKERNEL=y
 # CONFIG_ROMKERNEL is not set
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -131,20 +148,19 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
 # CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
 
 #
 # Executable file formats
@@ -168,7 +184,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -187,27 +202,21 @@ CONFIG_IP_FIB_HASH=y
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
 # CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_INET6_XFRM_TUNNEL is not set
 # CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -218,7 +227,6 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 
@@ -234,7 +242,17 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -245,16 +263,8 @@ CONFIG_TCP_CONG_BIC=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
 # CONFIG_MTD_CONCAT is not set
@@ -266,11 +276,13 @@ CONFIG_MTD_PARTITIONS=y
 # User Modules And Translation Layers
 #
 CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
 # CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -290,7 +302,6 @@ CONFIG_MTD_CFI_I2=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -313,42 +324,25 @@ CONFIG_MTD_UCLINUX=y
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
 # CONFIG_MTD_NAND is not set
-
-#
-# OneNAND Flash Device Drivers
-#
 # CONFIG_MTD_ONENAND is not set
 
 #
-# Parallel port support
+# UBI - Unsorted block images
 #
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+# CONFIG_MISC_DEVICES is not set
 # CONFIG_IDE is not set
 
 #
@@ -356,67 +350,29 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 #
 # CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 CONFIG_FEC=y
 # CONFIG_FEC2 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
+# Wireless LAN
 #
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 # CONFIG_WAN is not set
 CONFIG_PPP=y
 # CONFIG_PPP_MULTILINK is not set
@@ -427,20 +383,14 @@ CONFIG_PPP=y
 # CONFIG_PPP_BSDCOMP is not set
 # CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
 # CONFIG_SLIP is not set
+CONFIG_SLHC=y
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -472,34 +422,13 @@ CONFIG_SERIAL_COLDFIRE=y
 # CONFIG_UNIX98_PTYS is not set
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
 # CONFIG_I2C is not set
 
 #
@@ -507,101 +436,74 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
 
 #
-# Misc devices
+# Multifunction device drivers
 #
+# CONFIG_MFD_SM501 is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
 
 #
-# Digital Video Broadcasting Devices
+# Graphics support
 #
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Graphics support
+# Display device support
 #
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
 # CONFIG_FB is not set
 
 #
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB_ARCH_HAS_EHCI is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
+# CONFIG_USB_SUPPORT is not set
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
 # CONFIG_NEW_LEDS is not set
+# CONFIG_RTC_CLASS is not set
 
 #
-# LED drivers
+# DMA Engine support
 #
+# CONFIG_DMA_ENGINE is not set
 
 #
-# LED Triggers
+# DMA Clients
 #
 
 #
-# InfiniBand support
+# DMA Devices
 #
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# Userspace I/O
 #
-
-#
-# Real Time Clock
-#
-# CONFIG_RTC_CLASS is not set
+# CONFIG_UIO is not set
 
 #
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
@@ -629,6 +531,7 @@ CONFIG_ROMFS_FS=y
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
@@ -645,7 +548,6 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
@@ -664,7 +566,6 @@ CONFIG_RAMFS=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -677,16 +578,22 @@ CONFIG_MSDOS_PARTITION=y
 #
 # CONFIG_NLS is not set
 
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
 #
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
 # CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
 # CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_UNWIND_INFO is not set
 # CONFIG_FULLDEBUG is not set
 # CONFIG_HIGHPROFILE is not set
 # CONFIG_BOOTPARAM is not set
@@ -699,20 +606,16 @@ CONFIG_LOG_BUF_SHIFT=14
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
-#
-# Hardware crypto devices
-#
-
 #
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 # CONFIG_CRC32 is not set
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_DMA=y
index 3f86ade..74bf949 100644 (file)
@@ -151,27 +151,15 @@ void setup_arch(char **cmdline_p)
 #ifdef CONFIG_ELITE
        printk(KERN_INFO "Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n");
 #endif
-#ifdef CONFIG_TELOS
-       printk(KERN_INFO "Modified for Omnia ToolVox by James D. Schettine, james@telos-systems.com\n");
-#endif
 #endif
        printk(KERN_INFO "Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n");
 
 #if defined( CONFIG_PILOT ) && defined( CONFIG_M68328 )
        printk(KERN_INFO "TRG SuperPilot FLASH card support <info@trgnet.com>\n");
 #endif
-
 #if defined( CONFIG_PILOT ) && defined( CONFIG_M68EZ328 )
        printk(KERN_INFO "PalmV support by Lineo Inc. <jeff@uclinux.com>\n");
 #endif
-
-#ifdef CONFIG_M68EZ328ADS
-       printk(KERN_INFO "M68EZ328ADS board support (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>\n");
-#endif
-
-#ifdef CONFIG_ALMA_ANS
-       printk(KERN_INFO "Alma Electronics board support (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>\n");
-#endif
 #if defined (CONFIG_M68360)
        printk(KERN_INFO "QUICC port done by SED Systems <hamilton@sedsystems.ca>,\n");
        printk(KERN_INFO "based on 2.0.38 port by Lineo Inc. <mleslie@lineo.com>.\n");
@@ -188,11 +176,9 @@ void setup_arch(char **cmdline_p)
                "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
                (int) &_sdata, (int) &_edata,
                (int) &_sbss, (int) &_ebss);
-       printk(KERN_DEBUG "KERNEL -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x "
-               "STACK=0x%06x-0x%06x\n",
+       printk(KERN_DEBUG "MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ",
                (int) &_ebss, (int) memory_start,
-               (int) memory_start, (int) memory_end,
-               (int) memory_end, (int) _ramend);
+               (int) memory_start, (int) memory_end);
 #endif
 
        /* Keep a copy of command line */
@@ -287,12 +273,3 @@ struct seq_operations cpuinfo_op = {
        .show   = show_cpuinfo,
 };
 
-void arch_gettod(int *year, int *mon, int *day, int *hour,
-                int *min, int *sec)
-{
-       if (mach_gettod)
-               mach_gettod(year, mon, day, hour, min, sec);
-       else
-               *year = *mon = *day = *hour = *min = *sec = 0;
-}
-
index 437f8c6..7037137 100644 (file)
@@ -781,15 +781,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
        /* Did we come from a system call? */
        if (regs->orig_d0 >= 0) {
                /* Restart the system call - no handlers present */
-               if (regs->d0 == -ERESTARTNOHAND
-                   || regs->d0 == -ERESTARTSYS
-                   || regs->d0 == -ERESTARTNOINTR) {
-                       regs->d0 = regs->orig_d0;
-                       regs->pc -= 2;
-               } else if (regs->d0 == -ERESTART_RESTARTBLOCK) {
-                       regs->d0 = __NR_restart_syscall;
-                       regs->pc -= 2;
-               }
+               handle_restart(regs, NULL, 0);
        }
        return 0;
 }
index 467053d..77e5375 100644 (file)
@@ -27,7 +27,6 @@
 
 #define        TICK_SIZE (tick_nsec / 1000)
 
-
 static inline int set_rtc_mmss(unsigned long nowtime)
 {
        if (mach_set_clock_mmss)
@@ -39,15 +38,11 @@ static inline int set_rtc_mmss(unsigned long nowtime)
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-static irqreturn_t timer_interrupt(int irq, void *dummy)
+irqreturn_t arch_timer_interrupt(int irq, void *dummy)
 {
        /* last time the cmos clock got updated */
        static long last_rtc_update=0;
 
-       /* may need to kick the hardware timer */
-       if (mach_tick)
-         mach_tick();
-
        write_seqlock(&xtime_lock);
 
        do_timer(1);
@@ -103,10 +98,10 @@ void time_init(void)
 {
        unsigned int year, mon, day, hour, min, sec;
 
-       extern void arch_gettod(int *year, int *mon, int *day, int *hour,
-                               int *min, int *sec);
-
-       arch_gettod(&year, &mon, &day, &hour, &min, &sec);
+       if (mach_gettod)
+               mach_gettod(&year, &mon, &day, &hour, &min, &sec);
+       else
+               year = mon = day = hour = min = sec = 0;
 
        if ((year += 1900) < 1970)
                year += 100;
@@ -114,7 +109,7 @@ void time_init(void)
        xtime.tv_nsec = 0;
        wall_to_monotonic.tv_sec = -xtime.tv_sec;
 
-       mach_sched_init(timer_interrupt);
+       hw_timer_init();
 }
 
 /*
@@ -128,7 +123,7 @@ void do_gettimeofday(struct timeval *tv)
 
        do {
                seq = read_seqbegin_irqsave(&xtime_lock, flags);
-               usec = mach_gettimeoffset ? mach_gettimeoffset() : 0;
+               usec = hw_timer_offset();
                sec = xtime.tv_sec;
                usec += (xtime.tv_nsec / 1000);
        } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
@@ -160,8 +155,7 @@ int do_settimeofday(struct timespec *tv)
         * Discover what correction gettimeofday
         * would have done, and then undo it!
         */
-       if (mach_gettimeoffset)
-               nsec -= (mach_gettimeoffset() * 1000);
+       nsec -= (hw_timer_offset() * 1000);
 
        wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
        wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
index d0f2dc5..b3c4dd4 100644 (file)
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcftimer.h>
@@ -25,9 +22,6 @@
 
 /***************************************************************************/
 
-void coldfire_tick(void);
-void coldfire_timer_init(irq_handler_t handler);
-unsigned long coldfire_timer_offset(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -97,9 +91,6 @@ int mcf_timerirqpending(int timer)
 void config_BSP(char *commandp, int size)
 {
        mcf_setimr(MCFSIM_IMR_MASKALL);
-       mach_sched_init = coldfire_timer_init;
-       mach_tick = coldfire_tick;
-       mach_gettimeoffset = coldfire_timer_offset;
        mach_reset = coldfire_reset;
 }
 
index 425703f..f84a4ae 100644 (file)
@@ -9,23 +9,16 @@
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
-#include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
 
 /***************************************************************************/
 
-void coldfire_tick(void);
-void coldfire_timer_init(irq_handler_t handler);
-unsigned long coldfire_timer_offset(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -102,9 +95,6 @@ void config_BSP(char *commandp, int size)
        commandp[size-1] = 0;
 #endif /* CONFIG_NETtel */
 
-       mach_sched_init = coldfire_timer_init;
-       mach_tick = coldfire_tick;
-       mach_gettimeoffset = coldfire_timer_offset;
        mach_reset = coldfire_reset;
 }
 
index a2c95be..6edbd41 100644 (file)
@@ -27,9 +27,6 @@ unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
 
 /***************************************************************************/
 
-void coldfire_pit_tick(void);
-void coldfire_pit_init(irq_handler_t handler);
-unsigned long coldfire_pit_offset(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -47,10 +44,7 @@ void mcf_autovector(unsigned int vec)
 
 void config_BSP(char *commandp, int size)
 {
-    mach_sched_init = coldfire_pit_init;
-    mach_tick = coldfire_pit_tick;
-    mach_gettimeoffset = coldfire_pit_offset;
-    mach_reset = coldfire_reset;
+       mach_reset = coldfire_reset;
 }
 
 /***************************************************************************/
index 0a3af05..e7f80c8 100644 (file)
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -26,9 +24,6 @@
 
 /***************************************************************************/
 
-void coldfire_pit_tick(void);
-void coldfire_pit_init(irq_handler_t handler);
-unsigned long coldfire_pit_offset(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -62,9 +57,6 @@ void mcf_autovector(unsigned int vec)
 void config_BSP(char *commandp, int size)
 {
        mcf_disableall();
-       mach_sched_init = coldfire_pit_init;
-       mach_tick = coldfire_pit_tick;
-       mach_gettimeoffset = coldfire_pit_offset;
        mach_reset = coldfire_reset;
 }
 
index dc2c362..d4d3943 100644 (file)
@@ -9,24 +9,17 @@
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
-#include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
 
 /***************************************************************************/
 
-void coldfire_tick(void);
-void coldfire_timer_init(irq_handler_t handler);
-unsigned long coldfire_timer_offset(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -95,9 +88,6 @@ int mcf_timerirqpending(int timer)
 void config_BSP(char *commandp, int size)
 {
        mcf_setimr(MCFSIM_IMR_MASKALL);
-       mach_sched_init = coldfire_timer_init;
-       mach_tick = coldfire_tick;
-       mach_gettimeoffset = coldfire_timer_offset;
        mach_reset = coldfire_reset;
 }
 
index 1365a83..634a637 100644 (file)
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
-#include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
 
 /***************************************************************************/
 
-void coldfire_tick(void);
-void coldfire_timer_init(irq_handler_t handler);
-unsigned long coldfire_timer_offset(void);
 void coldfire_reset(void);
 
 extern unsigned int mcf_timervector;
@@ -128,9 +121,6 @@ void config_BSP(char *commandp, int size)
 
        mcf_timervector = 69;
        mcf_profilevector = 70;
-       mach_sched_init = coldfire_timer_init;
-       mach_tick = coldfire_tick;
-       mach_gettimeoffset = coldfire_timer_offset;
        mach_reset = coldfire_reset;
 }
 
index 1b82044..9cbfbc6 100644 (file)
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -26,9 +24,6 @@
 
 /***************************************************************************/
 
-void coldfire_pit_tick(void);
-void coldfire_pit_init(irq_handler_t handler);
-unsigned long coldfire_pit_offset(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -62,9 +57,6 @@ void mcf_autovector(unsigned int vec)
 void config_BSP(char *commandp, int size)
 {
        mcf_disableall();
-       mach_sched_init = coldfire_pit_init;
-       mach_tick = coldfire_pit_tick;
-       mach_gettimeoffset = coldfire_pit_offset;
        mach_reset = coldfire_reset;
 }
 
index a089e95..acbd434 100644 (file)
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -26,9 +24,6 @@
 
 /***************************************************************************/
 
-void coldfire_pit_tick(void);
-void coldfire_pit_init(irq_handler_t handler);
-unsigned long coldfire_pit_offset(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -62,9 +57,6 @@ void mcf_autovector(unsigned int vec)
 void config_BSP(char *commandp, int size)
 {
        mcf_disableall();
-       mach_sched_init = coldfire_pit_init;
-       mach_tick = coldfire_pit_tick;
-       mach_gettimeoffset = coldfire_pit_offset;
        mach_reset = coldfire_reset;
 }
 
index e346161..6040821 100644 (file)
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
-#include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
 #include <asm/mcfwdebug.h>
 
 /***************************************************************************/
 
-void coldfire_tick(void);
-void coldfire_timer_init(irq_handler_t handler);
-unsigned long coldfire_timer_offset(void);
 void coldfire_reset(void);
 
 extern unsigned int mcf_timervector;
@@ -122,9 +115,6 @@ void config_BSP(char *commandp, int size)
        mcf_timerlevel = 6;
 #endif
 
-       mach_sched_init = coldfire_timer_init;
-       mach_tick = coldfire_tick;
-       mach_gettimeoffset = coldfire_timer_offset;
        mach_reset = coldfire_reset;
 
 #ifdef MCF_BDM_DISABLE
index a8cd867..b333731 100644 (file)
@@ -74,7 +74,8 @@ ENTRY(system_call)
        movel   %sp,%d2                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d2       /* at start of kernel stack */
        movel   %d2,%a0
-       movel   %sp,%a0@(THREAD_ESP0)   /* save top of frame */
+       movel   %a0@,%a1                /* save top of frame */
+       movel   %sp,%a1@(TASK_THREAD+THREAD_ESP0)
        btst    #(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
        bnes    1f
 
@@ -83,6 +84,8 @@ ENTRY(system_call)
        movel   %d0,%sp@(PT_D0)         /* save the return value */
        jra     ret_from_exception
 1:
+       movel   #-ENOSYS,%d2            /* strace needs -ENOSYS in PT_D0 */
+       movel   %d2,PT_D0(%sp)          /* on syscall entry */
        subql   #4,%sp
        SAVE_SWITCH_STACK
        jbsr    syscall_trace
index f18352f..173b754 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/coldfire.h>
 #include <asm/mcfpit.h>
 
 /***************************************************************************/
 
-void coldfire_pit_tick(void)
+static irqreturn_t hw_tick(int irq, void *dummy)
 {
        unsigned short pcsr;
 
        /* Reset the ColdFire timer */
        pcsr = __raw_readw(TA(MCFPIT_PCSR));
        __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
+
+       return arch_timer_interrupt(irq, dummy);
 }
 
 /***************************************************************************/
 
 static struct irqaction coldfire_pit_irq = {
-       .name    = "timer",
-       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = hw_tick,
 };
 
-void coldfire_pit_init(irq_handler_t handler)
+void hw_timer_init(void)
 {
        volatile unsigned char *icrp;
        volatile unsigned long *imrp;
 
-       coldfire_pit_irq.handler = handler;
        setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &coldfire_pit_irq);
 
        icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
@@ -71,7 +74,7 @@ void coldfire_pit_init(irq_handler_t handler)
 
 /***************************************************************************/
 
-unsigned long coldfire_pit_offset(void)
+unsigned long hw_timer_offset(void)
 {
        volatile unsigned long *ipr;
        unsigned long pmr, pcntr, offset;
index 64bd0ff..489dec8 100644 (file)
@@ -9,10 +9,9 @@
 /***************************************************************************/
 
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/param.h>
 #include <linux/interrupt.h>
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <asm/io.h>
 #include <asm/traps.h>
@@ -54,24 +53,28 @@ extern int mcf_timerirqpending(int timer);
 
 /***************************************************************************/
 
-void coldfire_tick(void)
+static irqreturn_t hw_tick(int irq, void *dummy)
 {
        /* Reset the ColdFire timer */
        __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
+
+       return arch_timer_interrupt(irq, dummy);
 }
 
 /***************************************************************************/
 
 static struct irqaction coldfire_timer_irq = {
-        .name    = "timer",
-        .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = hw_tick,
 };
 
+/***************************************************************************/
+
 static int ticks_per_intr;
 
-void coldfire_timer_init(irq_handler_t handler)
+void hw_timer_init(void)
 {
-       coldfire_timer_irq.handler = handler;
        setup_irq(mcf_timervector, &coldfire_timer_irq);
 
        __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
@@ -89,7 +92,7 @@ void coldfire_timer_init(irq_handler_t handler)
 
 /***************************************************************************/
 
-unsigned long coldfire_timer_offset(void)
+unsigned long hw_timer_offset(void)
 {
        unsigned long tcn, offset;
 
index b32c642..f77328b 100644 (file)
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
-#include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
 #include <asm/mcfwdebug.h>
 
 /***************************************************************************/
 
-void coldfire_tick(void);
-void coldfire_timer_init(irq_handler_t handler);
-unsigned long coldfire_timer_offset(void);
 void coldfire_reset(void);
 
 extern unsigned int mcf_timervector;
@@ -104,9 +97,6 @@ void config_BSP(char *commandp, int size)
 
        mcf_timervector = 64+32;
        mcf_profilevector = 64+33;
-       mach_sched_init = coldfire_timer_init;
-       mach_tick = coldfire_tick;
-       mach_gettimeoffset = coldfire_timer_offset;
        mach_reset = coldfire_reset;
 
 #ifdef MCF_BDM_DISABLE
index e692536..2d3b62e 100644 (file)
 /***************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
-#include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfdma.h>
 
 /***************************************************************************/
 
-void coldfire_tick(void);
-void coldfire_timer_init(irq_handler_t handler);
-unsigned long coldfire_timer_offset(void);
 void coldfire_reset(void);
 
 extern unsigned int mcf_timervector;
@@ -108,9 +101,6 @@ void config_BSP(char *commandp, int size)
        mcf_timerlevel = 6;
 #endif
 
-       mach_sched_init = coldfire_timer_init;
-       mach_tick = coldfire_tick;
-       mach_gettimeoffset = coldfire_timer_offset;
        mach_reset = coldfire_reset;
 }
 
index 3ecff5e..61262c5 100644 (file)
@@ -66,6 +66,7 @@ config BCM47XX
 config MIPS_COBALT
        bool "Cobalt Server"
        select CEVT_R4K
+       select CEVT_GT641XX
        select DMA_NONCOHERENT
        select HW_HAS_PCI
        select I8253
@@ -729,6 +730,9 @@ config ARCH_MAY_HAVE_PC_FDC
 config BOOT_RAW
        bool
 
+config CEVT_GT641XX
+       bool
+
 config CEVT_R4K
        bool
 
index 3efe117..fd7124c 100644 (file)
@@ -6,18 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
-config CROSSCOMPILE
-       bool "Are you using a crosscompiler"
-       help
-         Say Y here if you are compiling the kernel on a different
-         architecture than the one it is intended to run on.  This is just a
-         convenience option which will select the appropriate value for
-         the CROSS_COMPILE make variable which otherwise has to be passed on
-         the command line from mips-linux-, mipsel-linux-, mips64-linux- and
-         mips64el-linux- as appropriate for a particular kernel configuration.
-         You will have to pass the value for CROSS_COMPILE manually if the
-         name prefix for your tools is different.
-
 config CMDLINE
        string "Default kernel command string"
        default ""
index 14164c2..23c1775 100644 (file)
@@ -18,15 +18,15 @@ cflags-y :=
 # Select the object file format to substitute into the linker script.
 #
 ifdef CONFIG_CPU_LITTLE_ENDIAN
-32bit-tool-prefix      = mipsel-linux-
-64bit-tool-prefix      = mips64el-linux-
+32bit-tool-archpref    = mipsel
+64bit-tool-archpref    = mips64el
 32bit-bfd              = elf32-tradlittlemips
 64bit-bfd              = elf64-tradlittlemips
 32bit-emul             = elf32ltsmip
 64bit-emul             = elf64ltsmip
 else
-32bit-tool-prefix      = mips-linux-
-64bit-tool-prefix      = mips64-linux-
+32bit-tool-archpref    = mips
+64bit-tool-archpref    = mips64
 32bit-bfd              = elf32-tradbigmips
 64bit-bfd              = elf64-tradbigmips
 32bit-emul             = elf32btsmip
@@ -34,16 +34,18 @@ else
 endif
 
 ifdef CONFIG_32BIT
-tool-prefix            = $(32bit-tool-prefix)
+tool-archpref          = $(32bit-tool-archpref)
 UTS_MACHINE            := mips
 endif
 ifdef CONFIG_64BIT
-tool-prefix            = $(64bit-tool-prefix)
+tool-archpref          = $(64bit-tool-archpref)
 UTS_MACHINE            := mips64
 endif
 
-ifdef CONFIG_CROSSCOMPILE
-CROSS_COMPILE          := $(tool-prefix)
+ifneq ($(SUBARCH),$(ARCH))
+  ifeq ($(CROSS_COMPILE),)
+    CROSS_COMPILE := $(call cc-cross-prefix, $(tool-archpref)-linux-  $(tool-archpref)-gnu-linux-  $(tool-archpref)-unknown-gnu-linux-)
+  endif
 endif
 
 ifdef CONFIG_32BIT
index 6b83f4d..d73833b 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the Cobalt micro systems family specific parts of the kernel
 #
 
-obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o
+obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o time.o
 
 obj-$(CONFIG_PCI)              += pci.o
 obj-$(CONFIG_EARLY_PRINTK)     += console.o
index d11bb1b..dd23beb 100644 (file)
@@ -9,19 +9,17 @@
  * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
  *
  */
-#include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
 #include <linux/pm.h>
 
 #include <asm/bootinfo.h>
-#include <asm/time.h>
-#include <asm/i8253.h>
-#include <asm/io.h>
 #include <asm/reboot.h>
 #include <asm/gt64120.h>
 
 #include <cobalt.h>
-#include <irq.h>
 
 extern void cobalt_machine_restart(char *command);
 extern void cobalt_machine_halt(void);
@@ -41,17 +39,6 @@ const char *get_system_type(void)
        return "MIPS Cobalt";
 }
 
-void __init plat_timer_setup(struct irqaction *irq)
-{
-       /* Load timer value for HZ (TCLK is 50MHz) */
-       GT_WRITE(GT_TC0_OFS, 50*1000*1000 / HZ);
-
-       /* Enable timer0 */
-       GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
-
-       setup_irq(GT641XX_TIMER0_IRQ, irq);
-}
-
 /*
  * Cobalt doesn't have PS/2 keyboard/mouse interfaces,
  * keyboard conntroller is never used.
@@ -84,11 +71,6 @@ static struct resource cobalt_reserved_resources[] = {
        },
 };
 
-void __init plat_time_init(void)
-{
-       setup_pit_timer();
-}
-
 void __init plat_mem_setup(void)
 {
        int i;
diff --git a/arch/mips/cobalt/time.c b/arch/mips/cobalt/time.c
new file mode 100644 (file)
index 0000000..fa819fc
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  Cobalt time initialization.
+ *
+ *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/init.h>
+
+#include <asm/gt64120.h>
+#include <asm/i8253.h>
+#include <asm/time.h>
+
+#define GT641XX_BASE_CLOCK     50000000        /* 50MHz */
+
+void __init plat_time_init(void)
+{
+       setup_pit_timer();
+
+       gt641xx_set_base_clock(GT641XX_BASE_CLOCK);
+
+       mips_timer_state = gt641xx_timer0_state;
+}
index a3afa39..d7745c8 100644 (file)
@@ -9,6 +9,7 @@ obj-y           += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
                   time.o topology.o traps.o unaligned.o
 
 obj-$(CONFIG_CEVT_R4K)         += cevt-r4k.o
+obj-$(CONFIG_CEVT_GT641XX)     += cevt-gt641xx.o
 
 binfmt_irix-objs       := irixelf.o irixinv.o irixioctl.o irixsig.o    \
                           irix5sys.o sysirix.o
diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c
new file mode 100644 (file)
index 0000000..4c651b2
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ *  GT641xx clockevent routines.
+ *
+ *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/gt64120.h>
+#include <asm/time.h>
+
+#include <irq.h>
+
+static DEFINE_SPINLOCK(gt641xx_timer_lock);
+static unsigned int gt641xx_base_clock;
+
+void gt641xx_set_base_clock(unsigned int clock)
+{
+       gt641xx_base_clock = clock;
+}
+
+int gt641xx_timer0_state(void)
+{
+       if (GT_READ(GT_TC0_OFS))
+               return 0;
+
+       GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
+       GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK);
+
+       return 1;
+}
+
+static int gt641xx_timer0_set_next_event(unsigned long delta,
+                                        struct clock_event_device *evt)
+{
+       unsigned long flags;
+       u32 ctrl;
+
+       spin_lock_irqsave(&gt641xx_timer_lock, flags);
+
+       ctrl = GT_READ(GT_TC_CONTROL_OFS);
+       ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
+       ctrl |= GT_TC_CONTROL_ENTC0_MSK;
+
+       GT_WRITE(GT_TC0_OFS, delta);
+       GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
+
+       spin_unlock_irqrestore(&gt641xx_timer_lock, flags);
+
+       return 0;
+}
+
+static void gt641xx_timer0_set_mode(enum clock_event_mode mode,
+                                   struct clock_event_device *evt)
+{
+       unsigned long flags;
+       u32 ctrl;
+
+       spin_lock_irqsave(&gt641xx_timer_lock, flags);
+
+       ctrl = GT_READ(GT_TC_CONTROL_OFS);
+       ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK;
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               ctrl |= GT_TC_CONTROL_ENTC0_MSK;
+               break;
+       default:
+               break;
+       }
+
+       GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
+
+       spin_unlock_irqrestore(&gt641xx_timer_lock, flags);
+}
+
+static void gt641xx_timer0_event_handler(struct clock_event_device *dev)
+{
+}
+
+static struct clock_event_device gt641xx_timer0_clockevent = {
+       .name           = "gt641xx-timer0",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .cpumask        = CPU_MASK_CPU0,
+       .irq            = GT641XX_TIMER0_IRQ,
+       .set_next_event = gt641xx_timer0_set_next_event,
+       .set_mode       = gt641xx_timer0_set_mode,
+       .event_handler  = gt641xx_timer0_event_handler,
+};
+
+static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *cd = &gt641xx_timer0_clockevent;
+
+       cd->event_handler(cd);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction gt641xx_timer0_irqaction = {
+       .handler        = gt641xx_timer0_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .name           = "gt641xx_timer0",
+};
+
+static int __init gt641xx_timer0_clockevent_init(void)
+{
+       struct clock_event_device *cd;
+
+       if (!gt641xx_base_clock)
+               return 0;
+
+       GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
+
+       cd = &gt641xx_timer0_clockevent;
+       cd->rating = 200 + gt641xx_base_clock / 10000000;
+       cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
+       cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
+       clockevent_set_clock(cd, gt641xx_base_clock);
+
+       clockevents_register_device(&gt641xx_timer0_clockevent);
+
+       return setup_irq(GT641XX_TIMER0_IRQ, &gt641xx_timer0_irqaction);
+}
+arch_initcall(gt641xx_timer0_clockevent_init);
index a915e56..ae2984f 100644 (file)
@@ -186,7 +186,7 @@ static int c0_compare_int_usable(void)
         * IP7 already pending?  Try to clear it by acking the timer.
         */
        if (c0_compare_int_pending()) {
-               write_c0_compare(read_c0_compare());
+               write_c0_compare(read_c0_count());
                irq_disable_hazard();
                if (c0_compare_int_pending())
                        return 0;
@@ -202,7 +202,7 @@ static int c0_compare_int_usable(void)
        if (!c0_compare_int_pending())
                return 0;
 
-       write_c0_compare(read_c0_compare());
+       write_c0_compare(read_c0_count());
        irq_disable_hazard();
        if (c0_compare_int_pending())
                return 0;
index c4e6866..6c6849a 100644 (file)
@@ -195,8 +195,8 @@ void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
 
        /* Find a shift value */
        for (shift = 32; shift > 0; shift--) {
-               temp = (u64) NSEC_PER_SEC << shift;
-               do_div(temp, clock);
+               temp = (u64) clock << shift;
+               do_div(temp, NSEC_PER_SEC);
                if ((temp >> 32) == 0)
                        break;
        }
index 1d00b77..9d6243a 100644 (file)
@@ -147,21 +147,8 @@ void __init plat_time_init(void)
 #endif
 }
 
-//static irqreturn_t mips_perf_interrupt(int irq, void *dev_id)
-//{
-//     return perf_irq();
-//}
-
-//static struct irqaction perf_irqaction = {
-//     .handler = mips_perf_interrupt,
-//     .flags = IRQF_DISABLED | IRQF_PERCPU,
-//     .name = "performance",
-//};
-
 void __init plat_perf_setup(void)
 {
-//     struct irqaction *irq = &perf_irqaction;
-
        cp0_perfcount_irq = -1;
 
 #ifdef MSC01E_INT_BASE
index 98b5e5b..b1b4052 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/scatterlist.h>
 
 #include <asm/cache.h>
 #include <asm/io.h>
@@ -165,12 +166,11 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        for (i = 0; i < nents; i++, sg++) {
                unsigned long addr;
 
-               addr = (unsigned long) page_address(sg->page);
+               addr = (unsigned long) sg_virt(sg);
                if (!plat_device_is_coherent(dev) && addr)
-                       __dma_sync(addr + sg->offset, sg->length, direction);
+                       __dma_sync(addr, sg->length, direction);
                sg->dma_address = plat_map_dma_mem(dev,
-                                                  (void *)(addr + sg->offset),
-                                                  sg->length);
+                                                  (void *)addr, sg->length);
        }
 
        return nents;
@@ -223,10 +223,9 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
        for (i = 0; i < nhwentries; i++, sg++) {
                if (!plat_device_is_coherent(dev) &&
                    direction != DMA_TO_DEVICE) {
-                       addr = (unsigned long) page_address(sg->page);
+                       addr = (unsigned long) sg_virt(sg);
                        if (addr)
-                               __dma_sync(addr + sg->offset, sg->length,
-                                          direction);
+                               __dma_sync(addr, sg->length, direction);
                }
                plat_unmap_dma_mem(sg->dma_address);
        }
@@ -304,7 +303,7 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
        /* Make sure that gcc doesn't leave the empty loop body.  */
        for (i = 0; i < nelems; i++, sg++) {
                if (cpu_is_noncoherent_r10000(dev))
-                       __dma_sync((unsigned long)page_address(sg->page),
+                       __dma_sync((unsigned long)page_address(sg_page(sg)),
                                   sg->length, direction);
                plat_unmap_dma_mem(sg->dma_address);
        }
@@ -322,7 +321,7 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nele
        /* Make sure that gcc doesn't leave the empty loop body.  */
        for (i = 0; i < nelems; i++, sg++) {
                if (!plat_device_is_coherent(dev))
-                       __dma_sync((unsigned long)page_address(sg->page),
+                       __dma_sync((unsigned long)page_address(sg_page(sg)),
                                   sg->length, direction);
                plat_unmap_dma_mem(sg->dma_address);
        }
index 681b593..3305fa9 100644 (file)
@@ -110,7 +110,7 @@ static void __init per_hub_init(cnodeid_t cnode)
        }
 }
 
-void __init per_cpu_init(void)
+void __cpuinit per_cpu_init(void)
 {
        int cpu = smp_processor_id();
        int slice = LOCAL_HUB_L(PI_CPU_NUM);
index d467bf4..f5dccf0 100644 (file)
@@ -111,8 +111,24 @@ unsigned long read_persistent_clock(void)
         return mktime(year, month, date, hour, min, sec);
 }
 
-static int rt_set_next_event(unsigned long delta,
-               struct clock_event_device *evt)
+static void enable_rt_irq(unsigned int irq)
+{
+}
+
+static void disable_rt_irq(unsigned int irq)
+{
+}
+
+static struct irq_chip rt_irq_type = {
+       .name           = "SN HUB RT timer",
+       .ack            = disable_rt_irq,
+       .mask           = disable_rt_irq,
+       .mask_ack       = disable_rt_irq,
+       .unmask         = enable_rt_irq,
+       .eoi            = enable_rt_irq,
+};
+
+static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
 {
        unsigned int cpu = smp_processor_id();
        int slice = cputoslice(cpu) == 0;
@@ -129,50 +145,24 @@ static void rt_set_mode(enum clock_event_mode mode,
                struct clock_event_device *evt)
 {
        switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
+       case CLOCK_EVT_MODE_ONESHOT:
                /* The only mode supported */
                break;
 
+       case CLOCK_EVT_MODE_PERIODIC:
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_SHUTDOWN:
-       case CLOCK_EVT_MODE_ONESHOT:
        case CLOCK_EVT_MODE_RESUME:
                /* Nothing to do  */
                break;
        }
 }
 
-struct clock_event_device rt_clock_event_device = {
-       .name           = "HUB-RT",
-       .features       = CLOCK_EVT_FEAT_ONESHOT,
-
-       .rating         = 300,
-       .set_next_event = rt_set_next_event,
-       .set_mode       = rt_set_mode,
-};
-
-static void enable_rt_irq(unsigned int irq)
-{
-}
-
-static void disable_rt_irq(unsigned int irq)
-{
-}
-
-static struct irq_chip rt_irq_type = {
-       .name           = "SN HUB RT timer",
-       .ack            = disable_rt_irq,
-       .mask           = disable_rt_irq,
-       .mask_ack       = disable_rt_irq,
-       .unmask         = enable_rt_irq,
-       .eoi            = enable_rt_irq,
-};
-
 unsigned int rt_timer_irq;
 
-static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id)
+static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
 {
-       struct clock_event_device *cd = &rt_clock_event_device;
+       struct clock_event_device *cd = dev_id;
        unsigned int cpu = smp_processor_id();
        int slice = cputoslice(cpu) == 0;
 
@@ -182,11 +172,10 @@ static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction rt_irqaction = {
-       .handler        = (irq_handler_t) ip27_rt_timer_interrupt,
-       .flags          = IRQF_DISABLED,
-       .mask           = CPU_MASK_NONE,
-       .name           = "timer"
+struct irqaction hub_rt_irqaction = {
+       .handler        = hub_rt_counter_handler,
+       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .name           = "hub-rt",
 };
 
 /*
@@ -200,32 +189,48 @@ static struct irqaction rt_irqaction = {
 #define NSEC_PER_CYCLE         800
 #define CYCLES_PER_SEC         (NSEC_PER_SEC / NSEC_PER_CYCLE)
 
-static void __init ip27_rt_clock_event_init(void)
+static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
+static DEFINE_PER_CPU(char [11], hub_rt_name);
+
+static void __cpuinit hub_rt_clock_event_init(void)
 {
-       struct clock_event_device *cd = &rt_clock_event_device;
        unsigned int cpu = smp_processor_id();
-       int irq = allocate_irqno();
-
-       if (irq < 0)
-               panic("Can't allocate interrupt number for timer interrupt");
-
-       rt_timer_irq = irq;
-
+       struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
+       unsigned char *name = per_cpu(hub_rt_name, cpu);
+       int irq = rt_timer_irq;
+
+       sprintf(name, "hub-rt %d", cpu);
+       cd->name                = "HUB-RT",
+       cd->features            = CLOCK_EVT_FEAT_ONESHOT,
+       clockevent_set_clock(cd, CYCLES_PER_SEC);
+       cd->max_delta_ns        = clockevent_delta2ns(0xfffffffffffff, cd);
+       cd->min_delta_ns        = clockevent_delta2ns(0x300, cd);
+       cd->rating              = 200,
        cd->irq                 = irq,
        cd->cpumask             = cpumask_of_cpu(cpu),
-
-       /*
-        * Calculate the min / max delta
-        */
-       cd->mult                =
-               div_sc((unsigned long) CYCLES_PER_SEC, NSEC_PER_SEC, 32);
-       cd->shift               = 32;
-       cd->max_delta_ns        = clockevent_delta2ns(0x7fffffff, cd);
-       cd->min_delta_ns        = clockevent_delta2ns(0x300, cd);
+       cd->rating              = 300,
+       cd->set_next_event      = rt_next_event,
+       cd->set_mode            = rt_set_mode,
        clockevents_register_device(cd);
+}
+
+static void __init hub_rt_clock_event_global_init(void)
+{
+       unsigned int irq;
+
+       do {
+               smp_wmb();
+               irq = rt_timer_irq;
+               if (irq)
+                       break;
+
+               irq = allocate_irqno();
+               if (irq < 0)
+                       panic("Allocation of irq number for timer failed");
+       } while (xchg(&rt_timer_irq, irq));
 
        set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq);
-       setup_irq(irq, &rt_irqaction);
+       setup_irq(irq, &hub_rt_irqaction);
 }
 
 static cycle_t hub_rt_read(void)
@@ -233,27 +238,29 @@ static cycle_t hub_rt_read(void)
        return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
 }
 
-struct clocksource ht_rt_clocksource = {
+struct clocksource hub_rt_clocksource = {
        .name   = "HUB-RT",
        .rating = 200,
        .read   = hub_rt_read,
        .mask   = CLOCKSOURCE_MASK(52),
-       .shift  = 32,
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static void __init ip27_rt_clocksource_init(void)
+static void __init hub_rt_clocksource_init(void)
 {
-       clocksource_register(&ht_rt_clocksource);
+       struct clocksource *cs = &hub_rt_clocksource;
+
+       clocksource_set_clock(cs, CYCLES_PER_SEC);
+       clocksource_register(cs);
 }
 
 void __init plat_time_init(void)
 {
-       ip27_rt_clock_event_init();
-       ip27_rt_clocksource_init();
+       hub_rt_clocksource_init();
+       hub_rt_clock_event_global_init();
 }
 
-void __init cpu_time_init(void)
+void __cpuinit cpu_time_init(void)
 {
        lboard_t *board;
        klcpu_t *cpu;
@@ -271,6 +278,7 @@ void __init cpu_time_init(void)
 
        printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
 
+       hub_rt_clock_event_init();
        set_c0_status(SRB_TIMOCLK);
 }
 
index 7aa79bf..10299ba 100644 (file)
@@ -452,6 +452,43 @@ static void bcm1480_kgdb_interrupt(void)
 
 extern void bcm1480_mailbox_interrupt(void);
 
+static inline void dispatch_ip4(void)
+{
+       int cpu = smp_processor_id();
+       int irq = K_BCM1480_INT_TIMER_0 + cpu;
+
+       /* Reset the timer */
+       __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
+                   IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
+
+       do_IRQ(irq);
+}
+
+static inline void dispatch_ip2(void)
+{
+       unsigned long long mask_h, mask_l;
+       unsigned int cpu = smp_processor_id();
+       unsigned long base;
+
+       /*
+        * Default...we've hit an IP[2] interrupt, which means we've got to
+        * check the 1480 interrupt registers to figure out what to do.  Need
+        * to detect which CPU we're on, now that smp_affinity is supported.
+        */
+       base = A_BCM1480_IMR_MAPPER(cpu);
+       mask_h = __raw_readq(
+               IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
+       mask_l = __raw_readq(
+               IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
+
+       if (mask_h) {
+               if (mask_h ^ 1)
+                       do_IRQ(fls64(mask_h) - 1);
+               else if (mask_l)
+                       do_IRQ(63 + fls64(mask_l));
+       }
+}
+
 asmlinkage void plat_irq_dispatch(void)
 {
        unsigned int pending;
@@ -469,17 +506,8 @@ asmlinkage void plat_irq_dispatch(void)
        else
 #endif
 
-       if (pending & CAUSEF_IP4) {
-               int cpu = smp_processor_id();
-               int irq = K_BCM1480_INT_TIMER_0 + cpu;
-
-               /* Reset the timer */
-               __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
-                           IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
-
-               do_IRQ(irq);
-       }
-
+       if (pending & CAUSEF_IP4)
+               dispatch_ip4();
 #ifdef CONFIG_SMP
        else if (pending & CAUSEF_IP3)
                bcm1480_mailbox_interrupt();
@@ -490,27 +518,6 @@ asmlinkage void plat_irq_dispatch(void)
                bcm1480_kgdb_interrupt();               /* KGDB (uart 1) */
 #endif
 
-       else if (pending & CAUSEF_IP2) {
-               unsigned long long mask_h, mask_l;
-               unsigned long base;
-
-               /*
-                * Default...we've hit an IP[2] interrupt, which means we've
-                * got to check the 1480 interrupt registers to figure out what
-                * to do.  Need to detect which CPU we're on, now that
-                * smp_affinity is supported.
-                */
-               base = A_BCM1480_IMR_MAPPER(smp_processor_id());
-               mask_h = __raw_readq(
-                       IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
-               mask_l = __raw_readq(
-                       IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
-
-               if (mask_h) {
-                       if (mask_h ^ 1)
-                               do_IRQ(fls64(mask_h) - 1);
-                       else
-                               do_IRQ(63 + fls64(mask_l));
-               }
-       }
+       else if (pending & CAUSEF_IP2)
+               dispatch_ip2();
 }
index 02b266a..436ba78 100644 (file)
@@ -58,7 +58,7 @@ static void *mailbox_0_regs[] = {
 /*
  * SMP init and finish on secondary CPUs
  */
-void bcm1480_smp_init(void)
+void __cpuinit bcm1480_smp_init(void)
 {
        unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
                STATUSF_IP1 | STATUSF_IP0;
@@ -67,7 +67,7 @@ void bcm1480_smp_init(void)
        change_c0_status(ST0_IM, imask);
 }
 
-void bcm1480_smp_finish(void)
+void __cpuinit bcm1480_smp_finish(void)
 {
        extern void sb1480_clockevent_init(void);
 
index c730744..610f025 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
-
-/*
- * These are routines to set up and handle interrupts from the
- * bcm1480 general purpose timer 0.  We're using the timer as a
- * system clock, so we set it up to run at 100 Hz.  On every
- * interrupt, we update our idea of what the time of day is,
- * then call do_timer() in the architecture-independent kernel
- * code to do general bookkeeping (e.g. update jiffies, run
- * bottom halves, etc.)
- */
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/percpu.h>
 #include <linux/spinlock.h>
 
-#include <asm/irq.h>
 #include <asm/addrspace.h>
 #include <asm/time.h>
 #include <asm/io.h>
 #define IMR_IP3_VAL    K_BCM1480_INT_MAP_I1
 #define IMR_IP4_VAL    K_BCM1480_INT_MAP_I2
 
-#ifdef CONFIG_SIMULATION
-#define BCM1480_HPT_VALUE      50000
-#else
-#define BCM1480_HPT_VALUE      1000000
-#endif
-
 extern int bcm1480_steal_irq(int irq);
 
-void __init plat_time_init(void)
-{
-       unsigned int cpu = smp_processor_id();
-       unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
-
-       BUG_ON(cpu > 3);        /* Only have 4 general purpose timers */
-
-       bcm1480_mask_irq(cpu, irq);
-
-       /* Map the timer interrupt to ip[4] of this cpu */
-       __raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H)
-             + (irq<<3)));
-
-       bcm1480_unmask_irq(cpu, irq);
-       bcm1480_steal_irq(irq);
-}
-
 /*
- * The general purpose timer ticks at 1 Mhz independent if
+ * The general purpose timer ticks at 1MHz independent if
  * the rest of the system
  */
 static void sibyte_set_mode(enum clock_event_mode mode,
@@ -88,7 +55,7 @@ static void sibyte_set_mode(enum clock_event_mode mode,
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
                __raw_writeq(0, timer_cfg);
-               __raw_writeq(BCM1480_HPT_VALUE / HZ - 1, timer_init);
+               __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init);
                __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
                             timer_cfg);
                break;
@@ -121,80 +88,96 @@ static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd)
        return res;
 }
 
-static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
-
 static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
 {
        unsigned int cpu = smp_processor_id();
-       struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
+       struct clock_event_device *cd = dev_id;
+       void __iomem *timer_cfg;
+
+       timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
 
        /* Reset the timer */
        __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
-                    IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
+                    timer_cfg);
        cd->event_handler(cd);
 
        return IRQ_HANDLED;
 }
 
-static struct irqaction sibyte_counter_irqaction = {
-       .handler        = sibyte_counter_handler,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU,
-       .name           = "timer",
-};
+static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
+static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
+static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
 
-/*
- * This interrupt is "special" in that it doesn't use the request_irq
- * way to hook the irq line.  The timer interrupt is initialized early
- * enough to make this a major pain, and it's also firing enough to
- * warrant a bit of special case code.  bcm1480_timer_interrupt is
- * called directly from irq_handler.S when IP[4] is set during an
- * interrupt
- */
 void __cpuinit sb1480_clockevent_init(void)
 {
        unsigned int cpu = smp_processor_id();
        unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
+       struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
        struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
+       unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
+
+       BUG_ON(cpu > 3);        /* Only have 4 general purpose timers */
 
-       cd->name                = "bcm1480-counter";
+       sprintf(name, "bcm1480-counter %d", cpu);
+       cd->name                = name;
        cd->features            = CLOCK_EVT_FEAT_PERIODIC |
                                  CLOCK_EVT_MODE_ONESHOT;
+       clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
+       cd->max_delta_ns        = clockevent_delta2ns(0x7fffff, cd);
+       cd->min_delta_ns        = clockevent_delta2ns(1, cd);
+       cd->rating              = 200;
+       cd->irq                 = irq;
+       cd->cpumask             = cpumask_of_cpu(cpu);
        cd->set_next_event      = sibyte_next_event;
        cd->set_mode            = sibyte_set_mode;
-       cd->irq                 = irq;
-       clockevent_set_clock(cd, BCM1480_HPT_VALUE);
+       clockevents_register_device(cd);
+
+       bcm1480_mask_irq(cpu, irq);
+
+       /*
+        * Map timer interrupt to IP[4] of this cpu
+        */
+       __raw_writeq(IMR_IP4_VAL,
+                    IOADDR(A_BCM1480_IMR_REGISTER(cpu,
+                       R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (irq << 3)));
 
-       setup_irq(irq, &sibyte_counter_irqaction);
+       bcm1480_unmask_irq(cpu, irq);
+       bcm1480_steal_irq(irq);
+
+       action->handler = sibyte_counter_handler;
+       action->flags   = IRQF_DISABLED | IRQF_PERCPU;
+       action->name    = name;
+       action->dev_id  = cd;
+       setup_irq(irq, action);
 }
 
 static cycle_t bcm1480_hpt_read(void)
 {
-       /* We assume this function is called xtime_lock held. */
-       unsigned long count =
-               __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT)));
-       return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count;
+       return (cycle_t) __raw_readq(IOADDR(A_SCD_ZBBUS_CYCLE_COUNT));
 }
 
 struct clocksource bcm1480_clocksource = {
-       .name   = "MIPS",
+       .name   = "zbbus-cycles",
        .rating = 200,
        .read   = bcm1480_hpt_read,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .shift  = 32,
+       .mask   = CLOCKSOURCE_MASK(64),
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 void __init sb1480_clocksource_init(void)
 {
        struct clocksource *cs = &bcm1480_clocksource;
+       unsigned int plldiv;
+       unsigned long zbbus;
 
-       clocksource_set_clock(cs, BCM1480_HPT_VALUE);
+       plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
+       zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000);
+       clocksource_set_clock(cs, zbbus);
        clocksource_register(cs);
 }
 
-void __init bcm1480_hpt_setup(void)
+void __init plat_time_init(void)
 {
-       mips_hpt_frequency = BCM1480_HPT_VALUE;
        sb1480_clocksource_init();
        sb1480_clockevent_init();
 }
index 500d17e..53780a1 100644 (file)
@@ -402,6 +402,22 @@ static void sb1250_kgdb_interrupt(void)
 
 extern void sb1250_mailbox_interrupt(void);
 
+static inline void dispatch_ip2(void)
+{
+       unsigned int cpu = smp_processor_id();
+       unsigned long long mask;
+
+       /*
+        * Default...we've hit an IP[2] interrupt, which means we've got to
+        * check the 1250 interrupt registers to figure out what to do.  Need
+        * to detect which CPU we're on, now that smp_affinity is supported.
+        */
+       mask = __raw_readq(IOADDR(A_IMR_REGISTER(cpu,
+                                 R_IMR_INTERRUPT_STATUS_BASE)));
+       if (mask)
+               do_IRQ(fls64(mask) - 1);
+}
+
 asmlinkage void plat_irq_dispatch(void)
 {
        unsigned int cpu = smp_processor_id();
@@ -434,21 +450,8 @@ asmlinkage void plat_irq_dispatch(void)
                sb1250_kgdb_interrupt();
 #endif
 
-       else if (pending & CAUSEF_IP2) {
-               unsigned long long mask;
-
-               /*
-                * Default...we've hit an IP[2] interrupt, which means we've
-                * got to check the 1250 interrupt registers to figure out what
-                * to do.  Need to detect which CPU we're on, now that
-                * smp_affinity is supported.
-                */
-               mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
-                                             R_IMR_INTERRUPT_STATUS_BASE)));
-               if (mask)
-                       do_IRQ(fls64(mask) - 1);
-               else
-                       spurious_interrupt();
-       } else
+       else if (pending & CAUSEF_IP2)
+               dispatch_ip2();
+       else
                spurious_interrupt();
 }
index aaa4f30..3f52c95 100644 (file)
@@ -46,7 +46,7 @@ static void *mailbox_regs[] = {
 /*
  * SMP init and finish on secondary CPUs
  */
-void sb1250_smp_init(void)
+void __cpuinit sb1250_smp_init(void)
 {
        unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
                STATUSF_IP1 | STATUSF_IP0;
@@ -55,7 +55,7 @@ void sb1250_smp_init(void)
        change_c0_status(ST0_IM, imask);
 }
 
-void sb1250_smp_finish(void)
+void __cpuinit sb1250_smp_finish(void)
 {
        extern void sb1250_clockevent_init(void);
 
index 9ef5462..a41e908 100644 (file)
 
 extern int sb1250_steal_irq(int irq);
 
-static cycle_t sb1250_hpt_read(void);
-
-void __init sb1250_hpt_setup(void)
-{
-       int cpu = smp_processor_id();
-
-       if (!cpu) {
-               /* Setup hpt using timer #3 but do not enable irq for it */
-               __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
-               __raw_writeq(SB1250_HPT_VALUE,
-                            IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT)));
-               __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
-                            IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
-
-               mips_hpt_frequency = V_SCD_TIMER_FREQ;
-               clocksource_mips.read = sb1250_hpt_read;
-               clocksource_mips.mask = M_SCD_TIMER_INIT;
-       }
-}
-
 /*
  * The general purpose timer ticks at 1 Mhz independent if
  * the rest of the system
@@ -121,18 +101,14 @@ sibyte_next_event(unsigned long delta, struct clock_event_device *evt)
        return 0;
 }
 
-struct clock_event_device sibyte_hpt_clockevent = {
-       .name           = "sb1250-counter",
-       .features       = CLOCK_EVT_FEAT_PERIODIC,
-       .set_mode       = sibyte_set_mode,
-       .set_next_event = sibyte_next_event,
-       .shift          = 32,
-       .irq            = 0,
-};
-
 static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
 {
-       struct clock_event_device *cd = &sibyte_hpt_clockevent;
+       unsigned int cpu = smp_processor_id();
+       struct clock_event_device *cd = dev_id;
+
+       /* ACK interrupt */
+       ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
+                      IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
 
        cd->event_handler(cd);
 
@@ -145,15 +121,35 @@ static struct irqaction sibyte_irqaction = {
        .name           = "timer",
 };
 
+static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
+static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
+static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
+
 void __cpuinit sb1250_clockevent_init(void)
 {
-       struct clock_event_device *cd = &sibyte_hpt_clockevent;
        unsigned int cpu = smp_processor_id();
-       int irq = K_INT_TIMER_0 + cpu;
+       unsigned int irq = K_INT_TIMER_0 + cpu;
+       struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
+       struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
+       unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
 
        /* Only have 4 general purpose timers, and we use last one as hpt */
        BUG_ON(cpu > 2);
 
+       sprintf(name, "bcm1480-counter %d", cpu);
+       cd->name                = name;
+       cd->features            = CLOCK_EVT_FEAT_PERIODIC |
+                                 CLOCK_EVT_MODE_ONESHOT;
+       clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
+       cd->max_delta_ns        = clockevent_delta2ns(0x7fffff, cd);
+       cd->min_delta_ns        = clockevent_delta2ns(1, cd);
+       cd->rating              = 200;
+       cd->irq                 = irq;
+       cd->cpumask             = cpumask_of_cpu(cpu);
+       cd->set_next_event      = sibyte_next_event;
+       cd->set_mode            = sibyte_set_mode;
+       clockevents_register_device(cd);
+
        sb1250_mask_irq(cpu, irq);
 
        /* Map the timer interrupt to ip[4] of this cpu */
@@ -165,17 +161,11 @@ void __cpuinit sb1250_clockevent_init(void)
        sb1250_unmask_irq(cpu, irq);
        sb1250_steal_irq(irq);
 
-       /*
-        * This interrupt is "special" in that it doesn't use the request_irq
-        * way to hook the irq line.  The timer interrupt is initialized early
-        * enough to make this a major pain, and it's also firing enough to
-        * warrant a bit of special case code.  sb1250_timer_interrupt is
-        * called directly from irq_handler.S when IP[4] is set during an
-        * interrupt
-        */
+       action->handler = sibyte_counter_handler;
+       action->flags   = IRQF_DISABLED | IRQF_PERCPU;
+       action->name    = name;
+       action->dev_id  = cd;
        setup_irq(irq, &sibyte_irqaction);
-
-       clockevents_register_device(cd);
 }
 
 /*
@@ -195,8 +185,7 @@ struct clocksource bcm1250_clocksource = {
        .name   = "MIPS",
        .rating = 200,
        .read   = sb1250_hpt_read,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .shift  = 32,
+       .mask   = CLOCKSOURCE_MASK(23),
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -204,6 +193,17 @@ void __init sb1250_clocksource_init(void)
 {
        struct clocksource *cs = &bcm1250_clocksource;
 
+       /* Setup hpt using timer #3 but do not enable irq for it */
+       __raw_writeq(0,
+                    IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
+                                                R_SCD_TIMER_CFG)));
+       __raw_writeq(SB1250_HPT_VALUE,
+                    IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
+                                                R_SCD_TIMER_INIT)));
+       __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
+                    IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
+                                                R_SCD_TIMER_CFG)));
+
        clocksource_set_clock(cs, V_SCD_TIMER_FREQ);
        clocksource_register(cs);
 }
index f3d0d7c..ae4a9b3 100644 (file)
 NM             = sh $(srctree)/arch/parisc/nm
 CHECKFLAGS     += -D__hppa__=1
 
+MACHINE                := $(shell uname -m)
+ifeq ($(MACHINE),parisc*)
+NATIVE         := 1
+endif
+
 ifdef CONFIG_64BIT
-CROSS_COMPILE  := $(shell if [ -x /usr/bin/hppa64-linux-gnu-gcc ]; then \
-                       echo hppa64-linux-gnu-; else echo hppa64-linux-; fi)
 UTS_MACHINE    := parisc64
 CHECKFLAGS     += -D__LP64__=1 -m64
-else
-MACHINE := $(subst 64,,$(shell uname -m))
-ifneq ($(MACHINE),parisc)
-CROSS_COMPILE  := hppa-linux-
-endif
+WIDTH          := 64
+CROSS_COMPILE  := hppa64-linux-gnu-
+else # 32-bit
+WIDTH          :=
 endif
 
-FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align 
+# attempt to help out folks who are cross-compiling
+ifeq ($(NATIVE),1)
+CROSS_COMPILE  := hppa$(WIDTH)-linux-
+endif
 
 OBJCOPY_FLAGS =-O binary -R .note -R .comment -S
 
-ifneq ($(call cc-ifversion, -lt, 0303, "bad"),)
-$(error Sorry, GCC v3.3 or above is required.)
-endif
-
 cflags-y       := -pipe
 
 # These flags should be implied by an hppa-linux configuration, but they
@@ -69,7 +70,7 @@ kernel-y                      := mm/ kernel/ math-emu/ kernel/init_task.o
 kernel-$(CONFIG_HPUX)          += hpux/
 
 core-y += $(addprefix arch/parisc/, $(kernel-y))
-libs-y += arch/parisc/lib/ `$(CC) -print-libgcc-file-name`
+libs-y += arch/parisc/lib/
 
 drivers-$(CONFIG_OPROFILE)             += arch/parisc/oprofile/
 
@@ -77,27 +78,27 @@ PALO := $(shell if which palo; then : ; \
        elif [ -x /sbin/palo ]; then echo /sbin/palo; \
        fi)
 
+PALOCONF := $(shell if [ -f $(src)/palo.conf ]; then echo $(src)/palo.conf; \
+       else echo $(obj)/palo.conf; \
+       fi)
+
 palo: vmlinux
-       @if [ -x $PALO ]; then \
+       @if test ! -x "$(PALO)"; then \
                echo 'ERROR: Please install palo first (apt-get install palo)';\
                echo 'or build it from source and install it somewhere in your $$PATH';\
                false; \
        fi
-       @if [ ! -f ./palo.conf ]; then \
-               cp arch/parisc/defpalo.conf palo.conf; \
-               echo 'A generic palo config file (./palo.conf) has been created for you.'; \
+       @if test ! -f "$(PALOCONF)"; then \
+               cp $(src)/arch/parisc/defpalo.conf $(obj)/palo.conf; \
+               echo 'A generic palo config file ($(obj)/palo.conf) has been created for you.'; \
                echo 'You should check it and re-run "make palo".'; \
                echo 'WARNING: the "lifimage" file is now placed in this directory by default!'; \
                false; \
        fi
-       $(PALO) -f ./palo.conf
-
-oldpalo: vmlinux
-       export TOPDIR=`pwd`; \
-       unset STRIP LDFLAGS CPP CPPFLAGS AFLAGS CFLAGS CC LD; cd ../palo && make lifimage
+       $(PALO) -f $(PALOCONF)
 
-# Shorthands for known targets not supported by parisc, use palo as default
-Image zImage bzImage: palo
+# Shorthands for known targets not supported by parisc, use vmlinux as default
+Image zImage bzImage: vmlinux
 
 kernel_install: vmlinux
        sh $(src)/arch/parisc/install.sh \
@@ -116,3 +117,12 @@ define archhelp
        @echo  '                  (distribution) /sbin/installkernel or'
        @echo  '                  copy to $$(INSTALL_PATH)'
 endef
+
+# we require gcc 3.3 or above to compile the kernel
+archprepare: checkbin
+checkbin:
+       @if test "$(call cc-version)" -lt "0303"; then \
+               echo -n "Sorry, GCC v3.3 or above is required to build " ; \
+               echo "the kernel." ; \
+               false ; \
+       fi
index 41fd069..9fc96e7 100644 (file)
@@ -1,39 +1,51 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-pa6
-# Sun Mar 26 19:59:51 2006
+# Linux kernel version: 2.6.23
+# Fri Oct 12 21:00:07 2007
 #
 CONFIG_PARISC=y
 CONFIG_MMU=y
 CONFIG_STACK_GROWSUP=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -43,31 +55,29 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -91,6 +101,9 @@ CONFIG_PA7100LC=y
 # CONFIG_PA7300LC is not set
 # CONFIG_PA8X00 is not set
 CONFIG_PA11=y
+CONFIG_PARISC_PAGE_SIZE_4KB=y
+# CONFIG_PARISC_PAGE_SIZE_16KB is not set
+# CONFIG_PARISC_PAGE_SIZE_64KB is not set
 # CONFIG_SMP is not set
 CONFIG_ARCH_FLATMEM_ENABLE=y
 # CONFIG_PREEMPT_NONE is not set
@@ -98,6 +111,7 @@ CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -108,6 +122,9 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_HPUX is not set
 
 #
@@ -120,21 +137,19 @@ CONFIG_GSC_LASI=y
 # CONFIG_GSC_WAX is not set
 # CONFIG_EISA is not set
 # CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
 
-#
-# PCI Hotplug Support
-#
-
 #
 # PA-RISC specific drivers
 #
 CONFIG_CHASSIS_LCD_LED=y
 # CONFIG_PDC_CHASSIS is not set
+CONFIG_PDC_CHASSIS_WARN=y
 CONFIG_PDC_STABLE=y
 
 #
@@ -151,13 +166,15 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -174,17 +191,23 @@ CONFIG_IP_PNP_BOOTP=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 # CONFIG_INET_IPCOMP is not set
-CONFIG_INET_TUNNEL=m
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=m
 CONFIG_INET_TCP_DIAG=m
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-
-#
-# IP: Virtual Server Configuration
-#
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
 # CONFIG_IP_VS is not set
 # CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
 
@@ -192,37 +215,18 @@ CONFIG_NETFILTER=y
 # Core Netfilter Configuration
 #
 # CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
 # CONFIG_NETFILTER_XTABLES is not set
 
 #
 # IP: Netfilter Configuration
 #
-CONFIG_IP_NF_CONNTRACK=m
-# CONFIG_IP_NF_CT_ACCT is not set
-CONFIG_IP_NF_CONNTRACK_MARK=y
-# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
-CONFIG_IP_NF_CT_PROTO_SCTP=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_NETBIOS_NS is not set
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-# CONFIG_IP_NF_PPTP is not set
 CONFIG_IP_NF_QUEUE=m
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -234,7 +238,6 @@ CONFIG_LLC2=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 
@@ -250,7 +253,17 @@ CONFIG_NET_PKTGEN=m
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -259,39 +272,24 @@ CONFIG_NET_PKTGEN=m
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=m
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
-CONFIG_PARPORT_NOT_PC=y
 CONFIG_PARPORT_GSC=y
+# CONFIG_PARPORT_AX88796 is not set
 # CONFIG_PARPORT_1284 is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+CONFIG_PARPORT_NOT_PC=y
+CONFIG_BLK_DEV=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
@@ -300,13 +298,11 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=6144
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 CONFIG_ATA_OVER_ETH=m
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_IDE is not set
 
 #
@@ -314,6 +310,9 @@ CONFIG_ATA_OVER_ETH=m
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
 
 #
@@ -333,104 +332,61 @@ CONFIG_CHR_DEV_SG=y
 # 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 Transport Attributes
+# SCSI Transports
 #
 CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_FC_ATTRS is not set
 CONFIG_SCSI_ISCSI_ATTRS=m
-# CONFIG_SCSI_SAS_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_IMM is not set
 CONFIG_SCSI_LASI700=y
 CONFIG_53C700_LE_ON_BE=y
 # CONFIG_SCSI_ZALON is not set
 CONFIG_SCSI_DEBUG=m
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_ATA is not set
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
 CONFIG_MD_RAID0=m
 CONFIG_MD_RAID1=m
 # CONFIG_MD_RAID10 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_RAID456 is not set
 # CONFIG_MD_MULTIPATH is not set
 # CONFIG_MD_FAULTY is not set
 # CONFIG_BLK_DEV_DM is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_TUN=m
-
-#
-# PHY device support
-#
+# CONFIG_VETH is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 CONFIG_LASI_82596=y
+# 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_B44 is not set
 # CONFIG_NET_POCKET is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
 
 #
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-# CONFIG_ATMEL is not set
-# CONFIG_HOSTAP is not set
-
-#
-# Wan interfaces
+# Wireless LAN
 #
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 # CONFIG_WAN is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=m
@@ -442,26 +398,22 @@ CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
 CONFIG_PPP_MPPE=m
 CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
 # CONFIG_SLIP is not set
+CONFIG_SLHC=m
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -486,14 +438,22 @@ CONFIG_KEYBOARD_ATKBD_HP_KEYCODES=y
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
 # CONFIG_KEYBOARD_HIL_OLD is not set
 CONFIG_KEYBOARD_HIL=y
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 CONFIG_MOUSE_SERIAL=m
 # CONFIG_MOUSE_VSXXXAA is not set
 CONFIG_MOUSE_HIL=m
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -516,6 +476,7 @@ CONFIG_SERIO_LIBPS2=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -523,6 +484,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_GSC=y
 CONFIG_SERIAL_8250_NR_UARTS=17
 CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
@@ -545,36 +507,15 @@ CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 CONFIG_PPDEV=m
 # CONFIG_TIPAR is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
 CONFIG_GEN_RTC=y
 CONFIG_GEN_RTC_X=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
 CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=256
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
 # CONFIG_I2C is not set
 
 #
@@ -582,46 +523,59 @@ CONFIG_MAX_RAW_DEVS=256
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
 
 #
-# Misc devices
+# Sonics Silicon Backplane
 #
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
-# Multimedia Capabilities Port drivers
+# Multifunction device drivers
 #
+# CONFIG_MFD_SM501 is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
 
 #
-# Digital Video Broadcasting Devices
+# Graphics support
 #
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Graphics support
+# Display device support
 #
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
 CONFIG_FB_STI=y
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
@@ -633,6 +587,7 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=128
 CONFIG_DUMMY_CONSOLE_ROWS=48
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
 CONFIG_FONTS=y
@@ -646,16 +601,11 @@ CONFIG_FONT_8x16=y
 # CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_SUN12x22 is not set
 # CONFIG_FONT_10x18 is not set
-
-#
-# Logo configuration
-#
 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_PARISC_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -673,9 +623,11 @@ CONFIG_SND_SEQUENCER=y
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
 CONFIG_SND_SEQUENCER_OSS=y
 # 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
 
@@ -685,8 +637,10 @@ CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
+# CONFIG_SND_MTS64 is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
+# CONFIG_SND_PORTMAN2X4 is not set
 
 #
 # GSC devices
@@ -694,15 +648,25 @@ CONFIG_SND_SUPPORT_OLD_API=y
 CONFIG_SND_HARMONY=y
 
 #
-# Open Sound System
+# System on Chip audio support
 #
-# CONFIG_SOUND_PRIME is not set
+# CONFIG_SND_SOC is not set
 
 #
-# USB support
+# SoC Audio support for SuperH
 #
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+CONFIG_USB_SUPPORT=y
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -712,19 +676,28 @@ CONFIG_SND_HARMONY=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_RTC_CLASS is not set
 
 #
-# MMC/SD Card support
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
 #
-# CONFIG_MMC is not set
 
 #
-# InfiniBand support
+# DMA Devices
 #
+# CONFIG_AUXDISPLAY is not set
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# Userspace I/O
 #
+# CONFIG_UIO is not set
 
 #
 # File systems
@@ -734,6 +707,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
@@ -744,15 +718,16 @@ CONFIG_JFS_FS=m
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
 CONFIG_XFS_FS=m
-CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -783,11 +758,12 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -795,6 +771,7 @@ CONFIG_RAMFS=y
 #
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
@@ -806,6 +783,8 @@ CONFIG_RAMFS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
 
 #
 # Network File Systems
@@ -827,6 +806,7 @@ CONFIG_EXPORTFS=m
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
 CONFIG_RPCSEC_GSS_KRB5=y
 CONFIG_RPCSEC_GSS_SPKM3=m
 CONFIG_SMB_FS=m
@@ -834,12 +814,13 @@ CONFIG_SMB_NLS_DEFAULT=y
 CONFIG_SMB_NLS_REMOTE="cp437"
 CONFIG_CIFS=m
 # CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
 # CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
 # CONFIG_CIFS_EXPERIMENTAL is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -891,6 +872,11 @@ CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=m
 
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
 #
 # Profiling support
 #
@@ -901,21 +887,32 @@ CONFIG_OPROFILE=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=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=y
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
 CONFIG_DEBUG_RODATA=y
 
 #
@@ -924,12 +921,13 @@ CONFIG_DEBUG_RODATA=y
 CONFIG_KEYS=y
 CONFIG_KEYS_DEBUG_PROC_KEYS=y
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MD5=y
@@ -938,9 +936,18 @@ CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_TGR192=m
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
@@ -949,21 +956,28 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_ANUBIS=m
+# CONFIG_CRYPTO_SEED is not set
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_CAMELLIA is not set
 CONFIG_CRYPTO_TEST=m
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_HW is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index f3b812f..ea07121 100644 (file)
@@ -1,73 +1,98 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-pa1
-# Fri Oct 21 23:04:54 2005
+# Linux kernel version: 2.6.23
+# Fri Oct 12 21:12:44 2007
 #
 CONFIG_PARISC=y
 CONFIG_MMU=y
 CONFIG_STACK_GROWSUP=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_TIME_LOW_RES=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
-CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_BLOCK_COMPAT=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
 
 #
 # Processor type and features
@@ -80,11 +105,23 @@ CONFIG_PA8X00=y
 CONFIG_PA20=y
 CONFIG_PREFETCH=y
 CONFIG_64BIT=y
+CONFIG_PARISC_PAGE_SIZE_4KB=y
+# CONFIG_PARISC_PAGE_SIZE_16KB is not set
+# CONFIG_PARISC_PAGE_SIZE_64KB is not set
 CONFIG_SMP=y
 CONFIG_HOTPLUG_CPU=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_NODES_SHIFT=3
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -95,7 +132,10 @@ CONFIG_DISCONTIGMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_NEED_MULTIPLE_NODES=y
 # CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_PREEMPT is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
 CONFIG_COMPAT=y
 CONFIG_NR_CPUS=8
 
@@ -104,7 +144,7 @@ CONFIG_NR_CPUS=8
 #
 # CONFIG_GSC is not set
 CONFIG_PCI=y
-CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCI_DEBUG is not set
 CONFIG_PCI_LBA=y
 CONFIG_IOSAPIC=y
@@ -124,13 +164,14 @@ CONFIG_CARDBUS=y
 # PC-card bridges
 #
 CONFIG_YENTA=m
+CONFIG_YENTA_O2=y
+CONFIG_YENTA_RICOH=y
+CONFIG_YENTA_TI=y
+CONFIG_YENTA_ENE_TUNE=y
+CONFIG_YENTA_TOSHIBA=y
 CONFIG_PD6729=m
 CONFIG_I82092=m
 CONFIG_PCCARD_NONSTATIC=m
-
-#
-# PCI Hotplug Support
-#
 # CONFIG_HOTPLUG_PCI is not set
 
 #
@@ -139,6 +180,7 @@ CONFIG_PCCARD_NONSTATIC=m
 # CONFIG_SUPERIO is not set
 # CONFIG_CHASSIS_LCD_LED is not set
 CONFIG_PDC_CHASSIS=y
+CONFIG_PDC_CHASSIS_WARN=y
 CONFIG_PDC_STABLE=y
 
 #
@@ -160,7 +202,10 @@ CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -177,97 +222,97 @@ CONFIG_IP_PNP_BOOTP=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
 CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-
-#
-# IP: Virtual Server Configuration
-#
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
 # CONFIG_IP_VS is not set
 CONFIG_IPV6=m
 # CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
 CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
 CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
 # CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
 
 #
 # IP: Netfilter Configuration
 #
-CONFIG_IP_NF_CONNTRACK=m
-# CONFIG_IP_NF_CT_ACCT is not set
-CONFIG_IP_NF_CONNTRACK_MARK=y
-# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
-CONFIG_IP_NF_CT_PROTO_SCTP=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_NETBIOS_NS is not set
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-# CONFIG_IP_NF_PPTP is not set
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
+# CONFIG_IP_NF_MATCH_AH is not set
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
 # CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_REALM is not set
-CONFIG_IP_NF_MATCH_SCTP=m
-# CONFIG_IP_NF_MATCH_DCCP is not set
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_HASHLIMIT=m
-# CONFIG_IP_NF_MATCH_STRING is not set
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-# CONFIG_IP_NF_TARGET_NFQUEUE is not set
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_NAT_AMANDA=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 # CONFIG_IP_NF_TARGET_TTL is not set
-CONFIG_IP_NF_TARGET_CONNMARK=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -277,48 +322,38 @@ CONFIG_IP_NF_ARP_MANGLE=m
 #
 # CONFIG_IP6_NF_QUEUE is not set
 CONFIG_IP6_NF_IPTABLES=m
-# CONFIG_IP6_NF_MATCH_LIMIT is not set
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
-# CONFIG_IP6_NF_MATCH_MULTIPORT is not set
 # CONFIG_IP6_NF_MATCH_OWNER is not set
-# CONFIG_IP6_NF_MATCH_MARK is not set
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-# CONFIG_IP6_NF_MATCH_AHESP is not set
-# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_AH is not set
+# CONFIG_IP6_NF_MATCH_MH is not set
 # CONFIG_IP6_NF_MATCH_EUI64 is not set
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-# CONFIG_IP6_NF_TARGET_NFQUEUE is not set
 CONFIG_IP6_NF_MANGLE=m
-# CONFIG_IP6_NF_TARGET_MARK is not set
 # CONFIG_IP6_NF_TARGET_HL is not set
 CONFIG_IP6_NF_RAW=m
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 CONFIG_IP_DCCP=m
 CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_DCCP_ACKVEC=y
 
 #
 # DCCP CCIDs Configuration (EXPERIMENTAL)
 #
+CONFIG_IP_DCCP_CCID2=m
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
 # CONFIG_IP_DCCP_CCID3 is not set
 
 #
 # DCCP Kernel Hacking
 #
 # CONFIG_IP_DCCP_DEBUG is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
@@ -329,11 +364,13 @@ CONFIG_LLC2=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -342,7 +379,17 @@ CONFIG_NET_PKTGEN=m
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -351,34 +398,17 @@ CONFIG_NET_PKTGEN=m
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -391,21 +421,14 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=6144
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
 # CONFIG_IDE is not set
 
 #
@@ -413,6 +436,9 @@ CONFIG_IOSCHED_CFQ=y
 #
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
 
 #
@@ -432,18 +458,18 @@ CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
-# SCSI Transport Attributes
+# SCSI Transports
 #
 CONFIG_SCSI_SPI_ATTRS=y
 CONFIG_SCSI_FC_ATTRS=m
 CONFIG_SCSI_ISCSI_ATTRS=m
-CONFIG_SCSI_SAS_ATTRS=m
-
-#
-# SCSI low-level drivers
-#
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
@@ -451,59 +477,40 @@ CONFIG_SCSI_SAS_ATTRS=m
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_HPTIOP is not set
 # CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
 CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=m
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
+CONFIG_SCSI_SYM53C8XX_MMIO=y
 CONFIG_SCSI_QLOGIC_1280=m
-# CONFIG_SCSI_QLOGIC_1280_1040 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-CONFIG_SCSI_QLA2300=m
-CONFIG_SCSI_QLA2322=m
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 CONFIG_SCSI_DEBUG=m
-
-#
-# PCMCIA SCSI adapter support
-#
-CONFIG_PCMCIA_FDOMAIN=m
-CONFIG_PCMCIA_QLOGIC=m
-CONFIG_PCMCIA_SYM53C500=m
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_ATA is not set
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
 # CONFIG_MD_RAID10 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_RAID456 is not set
 # CONFIG_MD_MULTIPATH is not set
 # CONFIG_MD_FAULTY is not set
 # CONFIG_BLK_DEV_DM is not set
@@ -517,39 +524,25 @@ CONFIG_FUSION_FC=m
 # CONFIG_FUSION_SAS is not set
 CONFIG_FUSION_MAX_SGE=128
 CONFIG_FUSION_CTL=m
+# CONFIG_FUSION_LOGGING is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_TUN=m
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
+# CONFIG_IP1000 is not set
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_HAPPYMEAL is not set
@@ -558,10 +551,6 @@ CONFIG_MII=m
 CONFIG_NET_VENDOR_3COM=y
 CONFIG_VORTEX=m
 CONFIG_TYPHOON=m
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 CONFIG_DE2104X=m
 CONFIG_TULIP=y
@@ -573,15 +562,18 @@ CONFIG_TULIP_MMIO=y
 # CONFIG_DM9102 is not set
 # CONFIG_ULI526X is not set
 CONFIG_PCMCIA_XIRCOM=m
-# CONFIG_PCMCIA_XIRTULIP is not set
 CONFIG_HP100=m
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=m
+# CONFIG_PCNET32_NAPI is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
 # CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=m
 # CONFIG_FEALNX is not set
@@ -593,84 +585,46 @@ CONFIG_E100=m
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+# CONFIG_SC92031 is not set
+CONFIG_NETDEV_1000=y
 CONFIG_ACENIC=m
 CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
 CONFIG_E1000=m
 CONFIG_E1000_NAPI=y
 # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_E1000E is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=m
 # CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-# CONFIG_PCMCIA_WAVELAN is not set
-CONFIG_PCMCIA_NETWAVE=m
-
-#
-# Wireless 802.11 Frequency Hopping cards support
-#
-CONFIG_PCMCIA_RAYCS=m
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-CONFIG_HERMES=m
-CONFIG_PLX_HERMES=m
-CONFIG_TMD_HERMES=m
-# CONFIG_NORTEL_HERMES is not set
-CONFIG_PCI_HERMES=m
-# CONFIG_ATMEL is not set
-
-#
-# Wireless 802.11b Pcmcia/Cardbus cards support
-#
-CONFIG_PCMCIA_HERMES=m
-# CONFIG_PCMCIA_SPECTRUM is not set
-CONFIG_AIRO_CS=m
-CONFIG_PCMCIA_WL3501=m
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
-#
-# CONFIG_PRISM54 is not set
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# PCMCIA network device support
+# Wireless LAN
 #
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 CONFIG_NET_PCMCIA=y
 CONFIG_PCMCIA_3C589=m
 CONFIG_PCMCIA_3C574=m
@@ -680,10 +634,6 @@ CONFIG_PCMCIA_3C574=m
 CONFIG_PCMCIA_SMC91C92=m
 CONFIG_PCMCIA_XIRC2PS=m
 # CONFIG_PCMCIA_AXNET is not set
-
-#
-# Wan interfaces
-#
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -694,28 +644,25 @@ CONFIG_PPP_ASYNC=m
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
 # CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
 # CONFIG_SLIP is not set
+CONFIG_SLHC=m
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -732,6 +679,7 @@ CONFIG_INPUT=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -747,6 +695,7 @@ CONFIG_INPUT=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -754,8 +703,10 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_CS=m
 CONFIG_SERIAL_8250_NR_UARTS=17
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -765,83 +716,73 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_MUX is not set
 CONFIG_PDC_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
 CONFIG_GEN_RTC=y
 CONFIG_GEN_RTC_X=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
+CONFIG_AGP=y
+CONFIG_AGP_PARISC=y
 # CONFIG_DRM is not set
 
 #
 # PCMCIA character devices
 #
 # CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
 CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=256
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
-# Dallas's 1-wire bus
+# SPI support
 #
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
 
 #
-# Misc devices
+# Sonics Silicon Backplane
 #
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
-# Multimedia Capabilities Port drivers
+# Multifunction device drivers
 #
+# CONFIG_MFD_SM501 is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
 
 #
-# Digital Video Broadcasting Devices
+# Graphics support
 #
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Graphics support
+# Display device support
 #
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
 # CONFIG_FB is not set
 
 #
@@ -856,33 +797,46 @@ CONFIG_DUMMY_CONSOLE_ROWS=64
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# USB support
-#
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
 # CONFIG_USB is not set
 
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
 #
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_RTC_CLASS is not set
 
 #
-# MMC/SD Card support
+# DMA Engine support
 #
-# CONFIG_MMC is not set
+# CONFIG_DMA_ENGINE is not set
 
 #
-# InfiniBand support
+# DMA Clients
 #
-# CONFIG_INFINIBAND is not set
 
 #
-# SN Devices
+# DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
 #
 # File systems
 #
@@ -891,6 +845,7 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
@@ -901,14 +856,16 @@ CONFIG_JFS_FS=m
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
 CONFIG_XFS_FS=m
-CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -939,18 +896,20 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
 #
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
@@ -963,6 +922,7 @@ CONFIG_RAMFS=y
 # CONFIG_SYSV_FS is not set
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
 
 #
 # Network File Systems
@@ -983,6 +943,7 @@ CONFIG_EXPORTFS=m
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
+# CONFIG_SUNRPC_BIND34 is not set
 CONFIG_RPCSEC_GSS_KRB5=m
 CONFIG_RPCSEC_GSS_SPKM3=m
 CONFIG_SMB_FS=m
@@ -990,12 +951,13 @@ CONFIG_SMB_NLS_DEFAULT=y
 CONFIG_SMB_NLS_REMOTE="cp437"
 CONFIG_CIFS=m
 # CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
 # CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
 # CONFIG_CIFS_EXPERIMENTAL is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1047,6 +1009,11 @@ CONFIG_NLS_ISO8859_15=m
 # CONFIG_NLS_KOI8_U is not set
 CONFIG_NLS_UTF8=m
 
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
 #
 # Profiling support
 #
@@ -1057,19 +1024,34 @@ CONFIG_OPROFILE=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
+CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_HEADERS_CHECK=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_IOREMAP is not set
-# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_RWLOCK is not set
+# CONFIG_DEBUG_RODATA is not set
 
 #
 # Security options
@@ -1077,12 +1059,13 @@ CONFIG_DETECT_SOFTLOCKUP=y
 CONFIG_KEYS=y
 CONFIG_KEYS_DEBUG_PROC_KEYS=y
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
 CONFIG_CRYPTO_NULL=m
 # CONFIG_CRYPTO_MD4 is not set
 CONFIG_CRYPTO_MD5=y
@@ -1091,32 +1074,47 @@ CONFIG_CRYPTO_SHA1=m
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
 CONFIG_CRYPTO_BLOWFISH=m
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
 # CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
+CONFIG_CRYPTO_CAST5=m
 # CONFIG_CRYPTO_CAST6 is not set
 # CONFIG_CRYPTO_TEA is not set
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
 # CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
 CONFIG_CRYPTO_DEFLATE=m
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_CAMELLIA is not set
 CONFIG_CRYPTO_TEST=m
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_HW is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 3509361..1bf22c9 100644 (file)
@@ -1,38 +1,47 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-rc1-pa0
-# Tue Jan 17 08:21:01 2006
+# Linux kernel version: 2.6.23
+# Fri Oct 12 21:16:46 2007
 #
 CONFIG_PARISC=y
 CONFIG_MMU=y
 CONFIG_STACK_GROWSUP=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 # CONFIG_EXPERIMENTAL is not set
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
-CONFIG_INITRAMFS_SOURCE=""
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_SYSCTL=y
 # 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
@@ -42,30 +51,27 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
 CONFIG_MODVERSIONS=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
-
-#
-# Block layer
-#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
 
 #
 # IO Schedulers
@@ -89,16 +95,26 @@ CONFIG_PA7100LC=y
 # CONFIG_PA7300LC is not set
 # CONFIG_PA8X00 is not set
 CONFIG_PA11=y
+CONFIG_PARISC_PAGE_SIZE_4KB=y
+# CONFIG_PARISC_PAGE_SIZE_16KB is not set
+# CONFIG_PARISC_PAGE_SIZE_64KB is not set
 # CONFIG_SMP is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_PREEMPT is not set
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_HPUX is not set
 
 #
@@ -113,7 +129,7 @@ CONFIG_EISA=y
 CONFIG_EISA_NAMES=y
 CONFIG_ISA=y
 CONFIG_PCI=y
-CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCI_DEBUG is not set
 CONFIG_GSC_DINO=y
 # CONFIG_PCI_LBA is not set
@@ -123,15 +139,12 @@ CONFIG_GSC_DINO=y
 #
 # CONFIG_PCCARD is not set
 
-#
-# PCI Hotplug Support
-#
-
 #
 # PA-RISC specific drivers
 #
 CONFIG_CHASSIS_LCD_LED=y
 # CONFIG_PDC_CHASSIS is not set
+CONFIG_PDC_CHASSIS_WARN=y
 CONFIG_PDC_STABLE=y
 
 #
@@ -151,6 +164,8 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -167,18 +182,32 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
 # CONFIG_INET6_AH is not set
 # CONFIG_INET6_ESP is not set
 # CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
 # CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_IPV6_SIT=y
 # CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
@@ -199,7 +228,14 @@ CONFIG_IPV6=y
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
 
 #
 # Device Drivers
@@ -208,39 +244,24 @@ CONFIG_IPV6=y
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
 # CONFIG_PARPORT_SERIAL is not set
-CONFIG_PARPORT_NOT_PC=y
 CONFIG_PARPORT_GSC=y
+# CONFIG_PARPORT_AX88796 is not set
 # CONFIG_PARPORT_1284 is not set
-
-#
-# Plug and Play support
-#
+CONFIG_PARPORT_NOT_PC=y
 # CONFIG_PNP is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
@@ -251,15 +272,13 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_RAM is not set
-CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
 CONFIG_ATA_OVER_ETH=y
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
 # CONFIG_IDE is not set
 
 #
@@ -267,6 +286,8 @@ CONFIG_ATA_OVER_ETH=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
 
 #
@@ -286,18 +307,17 @@ CONFIG_CHR_DEV_SG=y
 # 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 Transport Attributes
+# SCSI Transports
 #
 CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
@@ -308,12 +328,14 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
 # CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_ARCMSR is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_HPTIOP is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -327,23 +349,22 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_NCR53C406A is not set
 CONFIG_SCSI_LASI700=y
 CONFIG_53C700_LE_ON_BE=y
+# CONFIG_SCSI_STEX is not set
 CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 CONFIG_SCSI_SYM53C8XX_MMIO=y
-# CONFIG_SCSI_IPR is not set
 CONFIG_SCSI_ZALON=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=40
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_SYM53C416 is not set
@@ -351,22 +372,14 @@ CONFIG_SCSI_NCR53C8XX_SYNC=40
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_SCSI_SRP is not set
+# CONFIG_ATA is not set
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
-CONFIG_MD_RAID5=y
-CONFIG_MD_RAID6=y
+# CONFIG_MD_RAID456 is not set
 # CONFIG_MD_MULTIPATH is not set
 # CONFIG_MD_FAULTY is not set
 # CONFIG_BLK_DEV_DM is not set
@@ -382,35 +395,21 @@ CONFIG_MD_RAID6=y
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
-# I2O device support
+# An alternative FireWire stack is available with EXPERIMENTAL=y
 #
+# CONFIG_IEEE1394 is not set
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 CONFIG_LASI_82596=y
@@ -420,10 +419,6 @@ CONFIG_LASI_82596=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 CONFIG_TULIP=y
 # CONFIG_TULIP_MMIO is not set
@@ -435,62 +430,47 @@ CONFIG_TULIP=y
 # CONFIG_DEPCA is not set
 # CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
 # CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
 # CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+# CONFIG_QLA3XXX is not set
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-# CONFIG_ARLAN is not set
-# CONFIG_WAVELAN is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-# CONFIG_HERMES is not set
-# CONFIG_ATMEL is not set
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
-#
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# Wan interfaces
+# Wireless LAN
 #
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_PLIP is not set
@@ -501,24 +481,19 @@ CONFIG_PPP=y
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
 # CONFIG_SLIP is not set
+CONFIG_SLHC=y
 # CONFIG_NET_FC is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -543,19 +518,31 @@ CONFIG_KEYBOARD_ATKBD_HP_KEYCODES=y
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
 # CONFIG_KEYBOARD_HIL_OLD is not set
 CONFIG_KEYBOARD_HIL=y
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_INPORT is not set
 # CONFIG_MOUSE_LOGIBM is not set
 # CONFIG_MOUSE_PC110PAD is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 CONFIG_MOUSE_HIL=y
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_POWERMATE is not set
 # CONFIG_INPUT_UINPUT is not set
 # CONFIG_HP_SDC_RTC is not set
 
@@ -579,6 +566,7 @@ CONFIG_SERIO_LIBPS2=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -586,17 +574,20 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_GSC=y
+CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_NR_UARTS=13
 CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_RSA is not set
 # CONFIG_SERIAL_8250_FOURPORT is not set
 # CONFIG_SERIAL_8250_ACCENT is not set
 # CONFIG_SERIAL_8250_BOCA is not set
+# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set
 # CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
 
 #
 # Non-8250 serial port support
@@ -605,6 +596,7 @@ CONFIG_SERIAL_MUX=y
 CONFIG_SERIAL_MUX_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -612,35 +604,18 @@ CONFIG_PRINTER=y
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
 # CONFIG_TIPAR is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
 CONFIG_GEN_RTC=y
 # CONFIG_GEN_RTC_X is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
+# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -648,46 +623,59 @@ CONFIG_GEN_RTC=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
 
 #
-# Misc devices
+# Sonics Silicon Backplane
 #
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
-# Multimedia Capabilities Port drivers
+# Multifunction device drivers
 #
+# CONFIG_MFD_SM501 is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
 
 #
-# Digital Video Broadcasting Devices
+# Graphics support
 #
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Graphics support
+# Display device support
 #
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
 # CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
@@ -698,16 +686,18 @@ CONFIG_FB_STI=y
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON_OLD is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -717,21 +707,17 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
 CONFIG_DUMMY_CONSOLE_ROWS=64
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
 # CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
 CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
 CONFIG_LOGO_PARISC_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -749,8 +735,11 @@ CONFIG_SND_SEQUENCER=y
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
 CONFIG_SND_SEQUENCER_OSS=y
+# 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
 
@@ -760,13 +749,16 @@ CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
+# CONFIG_SND_MTS64 is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
+# CONFIG_SND_PORTMAN2X4 is not set
 
 #
 # PCI devices
 #
 # CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -778,6 +770,18 @@ CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS46XX is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_ENS1370 is not set
@@ -791,11 +795,13 @@ CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_KORG1212 is not set
 # CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_MIXART is not set
 # CONFIG_SND_NM256 is not set
 # CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
 # CONFIG_SND_RME32 is not set
 # CONFIG_SND_RME96 is not set
 # CONFIG_SND_RME9652 is not set
@@ -812,15 +818,25 @@ CONFIG_SND_SUPPORT_OLD_API=y
 CONFIG_SND_HARMONY=y
 
 #
-# Open Sound System
+# System on Chip audio support
 #
-# CONFIG_SOUND_PRIME is not set
+# CONFIG_SND_SOC is not set
 
 #
-# USB support
+# SoC Audio support for SuperH
+#
+
+#
+# Open Sound System
 #
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
 # CONFIG_USB is not set
 
 #
@@ -831,20 +847,29 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_RTC_CLASS is not set
 
 #
-# MMC/SD Card support
+# DMA Engine support
 #
-# CONFIG_MMC is not set
+# CONFIG_DMA_ENGINE is not set
 
 #
-# InfiniBand support
+# DMA Clients
 #
-# CONFIG_INFINIBAND is not set
 
 #
-# SN Devices
+# DMA Devices
 #
+# CONFIG_AUXDISPLAY is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
 
 #
 # File systems
@@ -860,9 +885,11 @@ CONFIG_JBD=y
 # 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_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -889,11 +916,12 @@ CONFIG_JOLIET=y
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -912,6 +940,7 @@ CONFIG_RAMFS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
 # CONFIG_NFSD_V3_ACL is not set
@@ -982,22 +1011,32 @@ CONFIG_NLS_UTF8=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_IOREMAP is not set
-# CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_RODATA is not set
 
 #
@@ -1007,13 +1046,10 @@ CONFIG_FORCED_INLINING=y
 CONFIG_SECURITY=y
 # CONFIG_SECURITY_NETWORK is not set
 CONFIG_SECURITY_CAPABILITIES=y
-# CONFIG_SECURITY_SECLVL is not set
-# CONFIG_SECURITY_SELINUX is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_NULL is not set
 # CONFIG_CRYPTO_MD4 is not set
@@ -1023,7 +1059,12 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 # CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
@@ -1034,19 +1075,26 @@ CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
 # CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_HW=y
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index eb2f9a3..c6def3c 100644 (file)
@@ -1,39 +1,50 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-pa6
-# Sun Mar 26 20:03:29 2006
+# Linux kernel version: 2.6.23
+# Fri Oct 12 21:24:00 2007
 #
 CONFIG_PARISC=y
 CONFIG_MMU=y
 CONFIG_STACK_GROWSUP=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
-CONFIG_INITRAMFS_SOURCE=""
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -43,31 +54,29 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -93,6 +102,9 @@ CONFIG_PA8X00=y
 CONFIG_PA20=y
 CONFIG_PREFETCH=y
 # CONFIG_64BIT is not set
+CONFIG_PARISC_PAGE_SIZE_4KB=y
+# CONFIG_PARISC_PAGE_SIZE_16KB is not set
+# CONFIG_PARISC_PAGE_SIZE_64KB is not set
 # CONFIG_SMP is not set
 CONFIG_ARCH_FLATMEM_ENABLE=y
 # CONFIG_PREEMPT_NONE is not set
@@ -100,6 +112,7 @@ CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -110,6 +123,9 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_HPUX is not set
 
 #
@@ -117,7 +133,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 #
 # CONFIG_GSC is not set
 CONFIG_PCI=y
-CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCI_DEBUG is not set
 CONFIG_PCI_LBA=y
 CONFIG_IOSAPIC=y
@@ -127,10 +143,6 @@ CONFIG_IOMMU_SBA=y
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
 # CONFIG_HOTPLUG_PCI is not set
 
 #
@@ -139,6 +151,7 @@ CONFIG_IOMMU_SBA=y
 CONFIG_SUPERIO=y
 CONFIG_CHASSIS_LCD_LED=y
 # CONFIG_PDC_CHASSIS is not set
+CONFIG_PDC_CHASSIS_WARN=y
 CONFIG_PDC_STABLE=y
 
 #
@@ -155,13 +168,15 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -178,22 +193,36 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-
-#
-# IP: Virtual Server Configuration
-#
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
 # CONFIG_IP_VS is not set
 CONFIG_IPV6=m
 # CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
 # CONFIG_INET6_AH is not set
 # CONFIG_INET6_ESP is not set
 CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
 CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
 CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_DEBUG=y
 
@@ -201,42 +230,24 @@ CONFIG_NETFILTER_DEBUG=y
 # Core Netfilter Configuration
 #
 # CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
 # CONFIG_NETFILTER_XTABLES is not set
 
 #
 # IP: Netfilter Configuration
 #
-CONFIG_IP_NF_CONNTRACK=m
-# CONFIG_IP_NF_CT_ACCT is not set
-# CONFIG_IP_NF_CONNTRACK_MARK is not set
-# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
-# CONFIG_IP_NF_CT_PROTO_SCTP is not set
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_NETBIOS_NS is not set
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-# CONFIG_IP_NF_PPTP is not set
 CONFIG_IP_NF_QUEUE=m
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
 
 #
 # IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 # CONFIG_IP6_NF_QUEUE is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
+# CONFIG_IP6_NF_IPTABLES is not set
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -247,7 +258,6 @@ CONFIG_IP_NF_QUEUE=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 
@@ -263,7 +273,17 @@ CONFIG_NET_PKTGEN=m
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -272,33 +292,17 @@ CONFIG_NET_PKTGEN=m
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -310,14 +314,15 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
-CONFIG_BLK_DEV_RAM_COUNT=16
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
 CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -331,19 +336,26 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 CONFIG_BLK_DEV_IDESCSI=y
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
 #
 CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
+CONFIG_IDEDMA_ONLYDISK=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
@@ -354,8 +366,10 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
 # CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
 # CONFIG_BLK_DEV_IT821X is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
@@ -365,10 +379,10 @@ CONFIG_BLK_DEV_SIIMAGE=m
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -376,6 +390,9 @@ CONFIG_BLK_DEV_IDEDMA=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
 
 #
@@ -395,18 +412,17 @@ CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
-# SCSI Transport Attributes
+# SCSI Transports
 #
 CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_FC_ATTRS is not set
 CONFIG_SCSI_ISCSI_ATTRS=m
-# CONFIG_SCSI_SAS_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
@@ -415,66 +431,53 @@ CONFIG_SCSI_ISCSI_ATTRS=m
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
 # CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_MEGARAID_SAS is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_AHCI is not set
-# CONFIG_SCSI_SATA_SVW is not set
-CONFIG_SCSI_ATA_PIIX=m
-# CONFIG_SCSI_SATA_MV is not set
-# CONFIG_SCSI_SATA_NV is not set
-# CONFIG_SCSI_PDC_ADMA is not set
-# CONFIG_SCSI_SATA_QSTOR is not set
-CONFIG_SCSI_SATA_PROMISE=m
-# CONFIG_SCSI_SATA_SX4 is not set
-CONFIG_SCSI_SATA_SIL=m
-# CONFIG_SCSI_SATA_SIL24 is not set
-# CONFIG_SCSI_SATA_SIS is not set
-# CONFIG_SCSI_SATA_ULI is not set
-CONFIG_SCSI_SATA_VIA=m
-# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SCSI_HPTIOP is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
 CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 CONFIG_SCSI_SYM53C8XX_MMIO=y
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 CONFIG_SCSI_DEBUG=m
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_SCSI_SRP is not set
+# CONFIG_ATA is not set
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
 # CONFIG_MD_RAID10 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_RAID456 is not set
 # CONFIG_MD_MULTIPATH is not set
 # CONFIG_MD_FAULTY is not set
 CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
 CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
 CONFIG_DM_MULTIPATH=m
 # CONFIG_DM_MULTIPATH_EMC is not set
+# CONFIG_DM_MULTIPATH_RDAC is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -485,49 +488,31 @@ CONFIG_FUSION_SPI=m
 # CONFIG_FUSION_SAS is not set
 CONFIG_FUSION_MAX_SGE=128
 CONFIG_FUSION_CTL=m
+# CONFIG_FUSION_LOGGING is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_TUN=m
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
+# CONFIG_IP1000 is not set
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 CONFIG_DE2104X=m
 CONFIG_TULIP=y
@@ -539,13 +524,16 @@ CONFIG_TULIP_MMIO=y
 # CONFIG_DM9102 is not set
 # CONFIG_ULI526X is not set
 # CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
 # CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=m
 # CONFIG_FEALNX is not set
@@ -558,16 +546,15 @@ CONFIG_E100=m
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+# CONFIG_SC92031 is not set
+CONFIG_NETDEV_1000=y
 CONFIG_ACENIC=m
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
 # CONFIG_DL2K is not set
 CONFIG_E1000=m
 # CONFIG_E1000_NAPI is not set
 # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_E1000E is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -579,27 +566,36 @@ CONFIG_E1000=m
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=m
 # CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -612,27 +608,23 @@ CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
 # CONFIG_PPP_MPPE is not set
 CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
 # CONFIG_SLIP is not set
+CONFIG_SLHC=m
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -655,11 +647,14 @@ CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_INPUT_MOUSE=y
 # CONFIG_MOUSE_PS2 is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -679,6 +674,7 @@ CONFIG_SERIO_LIBPS2=m
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -686,6 +682,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_NR_UARTS=13
 CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
@@ -704,38 +701,19 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
 CONFIG_GEN_RTC=y
 CONFIG_GEN_RTC_X=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
+# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 CONFIG_RAW_DRIVER=y
 CONFIG_MAX_RAW_DEVS=256
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -743,46 +721,59 @@ CONFIG_MAX_RAW_DEVS=256
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
 
 #
-# Misc devices
+# Sonics Silicon Backplane
 #
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
-# Multimedia Capabilities Port drivers
+# Multifunction device drivers
 #
+# CONFIG_MFD_SM501 is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
 
 #
-# Digital Video Broadcasting Devices
+# Graphics support
 #
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Graphics support
+# Display device support
 #
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
 # CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
@@ -793,17 +784,20 @@ CONFIG_FB_STI=y
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON_OLD is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
 # CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -813,21 +807,17 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=160
 CONFIG_DUMMY_CONSOLE_ROWS=64
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
 # CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
-
-#
-# Logo configuration
-#
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 CONFIG_LOGO_PARISC_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -845,9 +835,11 @@ CONFIG_SND_SEQUENCER=y
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
 CONFIG_SND_SEQUENCER_OSS=y
 # 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
 
@@ -855,7 +847,6 @@ CONFIG_SND_SUPPORT_OLD_API=y
 # Generic devices
 #
 CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
@@ -866,7 +857,7 @@ CONFIG_SND_AC97_BUS=y
 # PCI devices
 #
 CONFIG_SND_AD1889=y
-# CONFIG_SND_AD1889_OPL3 is not set
+# CONFIG_SND_ALS300 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -879,6 +870,18 @@ CONFIG_SND_AD1889=y
 # CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS46XX is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_ENS1370 is not set
@@ -898,6 +901,7 @@ CONFIG_SND_AD1889=y
 # CONFIG_SND_MIXART is not set
 # CONFIG_SND_NM256 is not set
 # CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
 # CONFIG_SND_RME32 is not set
 # CONFIG_SND_RME96 is not set
 # CONFIG_SND_RME9652 is not set
@@ -907,22 +911,43 @@ CONFIG_SND_AD1889=y
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
 # CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
 
 #
 # USB devices
 #
 # CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# SoC Audio support for SuperH
+#
 
 #
 # Open Sound System
 #
 # CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
 
 #
-# USB support
+# USB Input Devices
 #
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
 CONFIG_USB_DEBUG=y
 
@@ -930,7 +955,7 @@ CONFIG_USB_DEBUG=y
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_OTG is not set
 
@@ -940,15 +965,16 @@ CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_EHCI_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_UHCI_HCD is not set
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
 #
-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
 # CONFIG_USB_ACM is not set
 CONFIG_USB_PRINTER=m
 
@@ -970,54 +996,14 @@ CONFIG_USB_STORAGE_SDDR09=y
 CONFIG_USB_STORAGE_SDDR55=y
 CONFIG_USB_STORAGE_JUMPSHOT=y
 # CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
 # CONFIG_USB_LIBUSUAL is not set
 
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=y
-CONFIG_USB_HIDINPUT=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-CONFIG_USB_HIDDEV=y
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-
 #
 # USB Imaging devices
 #
 CONFIG_USB_MDC800=m
 CONFIG_USB_MICROTEK=m
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
 # CONFIG_USB_MON is not set
 
 #
@@ -1034,16 +1020,22 @@ CONFIG_USB_MICROTEK=m
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 CONFIG_USB_LEGOTOWER=m
 # 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_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
 # CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
 
 #
@@ -1054,21 +1046,29 @@ CONFIG_USB_LEGOTOWER=m
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_RTC_CLASS is not set
 
 #
-# MMC/SD Card support
+# DMA Engine support
 #
-# CONFIG_MMC is not set
+# CONFIG_DMA_ENGINE is not set
 
 #
-# InfiniBand support
+# DMA Clients
 #
-# CONFIG_INFINIBAND is not set
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
 #
 # File systems
 #
@@ -1077,21 +1077,23 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 CONFIG_XFS_FS=m
-CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -1121,11 +1123,12 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -1164,6 +1167,7 @@ CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -1171,7 +1175,6 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1223,6 +1226,11 @@ CONFIG_NLS_ISO8859_15=m
 # CONFIG_NLS_KOI8_U is not set
 CONFIG_NLS_UTF8=m
 
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
 #
 # Profiling support
 #
@@ -1233,21 +1241,32 @@ CONFIG_OPROFILE=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=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_INFO is not set
-# CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
 CONFIG_DEBUG_RODATA=y
 
 #
@@ -1255,12 +1274,12 @@ CONFIG_DEBUG_RODATA=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_MANAGER=m
 # CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
 CONFIG_CRYPTO_NULL=m
 # CONFIG_CRYPTO_MD4 is not set
 CONFIG_CRYPTO_MD5=m
@@ -1269,7 +1288,15 @@ CONFIG_CRYPTO_MD5=m
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
 CONFIG_CRYPTO_BLOWFISH=m
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
@@ -1280,21 +1307,28 @@ CONFIG_CRYPTO_BLOWFISH=m
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
 # CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
 CONFIG_CRYPTO_DEFLATE=m
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_CAMELLIA is not set
 CONFIG_CRYPTO_TEST=m
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_HW is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index b38b58e..448a757 100644 (file)
@@ -1,39 +1,51 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-pa10
-# Sun Apr  2 15:26:38 2006
+# Linux kernel version: 2.6.23
+# Fri Oct 12 20:54:57 2007
 #
 CONFIG_PARISC=y
 CONFIG_MMU=y
 CONFIG_STACK_GROWSUP=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -43,31 +55,29 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -101,6 +111,7 @@ CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -111,6 +122,9 @@ CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_HPUX is not set
 
 #
@@ -125,7 +139,7 @@ CONFIG_EISA=y
 CONFIG_EISA_NAMES=y
 # CONFIG_ISA is not set
 CONFIG_PCI=y
-CONFIG_PCI_LEGACY_PROC=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCI_DEBUG is not set
 CONFIG_GSC_DINO=y
 CONFIG_PCI_LBA=y
@@ -154,10 +168,6 @@ CONFIG_YENTA_TOSHIBA=y
 CONFIG_PD6729=y
 CONFIG_I82092=y
 CONFIG_PCCARD_NONSTATIC=y
-
-#
-# PCI Hotplug Support
-#
 # CONFIG_HOTPLUG_PCI is not set
 
 #
@@ -166,6 +176,7 @@ CONFIG_PCCARD_NONSTATIC=y
 CONFIG_SUPERIO=y
 CONFIG_CHASSIS_LCD_LED=y
 CONFIG_PDC_CHASSIS=y
+CONFIG_PDC_CHASSIS_WARN=y
 CONFIG_PDC_STABLE=y
 
 #
@@ -182,13 +193,15 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -205,33 +218,39 @@ CONFIG_IP_PNP_BOOTP=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 # CONFIG_INET_IPCOMP is not set
-CONFIG_INET_TUNNEL=m
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=m
 CONFIG_INET_TCP_DIAG=m
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
 CONFIG_INET6_AH=y
 CONFIG_INET6_ESP=y
 CONFIG_INET6_IPCOMP=y
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=y
 CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
 # CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -243,7 +262,6 @@ CONFIG_LLC2=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 
@@ -259,7 +277,17 @@ CONFIG_LLC2=m
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -268,41 +296,26 @@ CONFIG_LLC2=m
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=m
 # CONFIG_PARPORT_SERIAL is not set
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
 CONFIG_PARPORT_PC_PCMCIA=m
-CONFIG_PARPORT_NOT_PC=y
 CONFIG_PARPORT_GSC=y
+# CONFIG_PARPORT_AX88796 is not set
 CONFIG_PARPORT_1284=y
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+CONFIG_PARPORT_NOT_PC=y
+CONFIG_BLK_DEV=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
@@ -317,13 +330,14 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=6144
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDE=y
 
@@ -334,24 +348,32 @@ CONFIG_BLK_DEV_IDE=y
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
 CONFIG_BLK_DEV_IDECS=y
+# CONFIG_BLK_DEV_DELKIN is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 CONFIG_BLK_DEV_IDESCSI=y
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
 #
 CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
+CONFIG_IDEDMA_ONLYDISK=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
@@ -362,8 +384,10 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
 # CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
 # CONFIG_BLK_DEV_IT821X is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
@@ -373,10 +397,10 @@ CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -384,6 +408,9 @@ CONFIG_BLK_DEV_IDEDMA=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
 
 #
@@ -403,18 +430,17 @@ CONFIG_CHR_DEV_SG=y
 # 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 Transport Attributes
+# SCSI Transports
 #
 CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
@@ -424,11 +450,13 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
 # CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_HPTIOP is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_IPS is not set
@@ -438,55 +466,45 @@ CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_IMM is not set
 CONFIG_SCSI_LASI700=y
 CONFIG_53C700_LE_ON_BE=y
+# CONFIG_SCSI_STEX is not set
 CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 CONFIG_SCSI_SYM53C8XX_MMIO=y
-# CONFIG_SCSI_IPR is not set
 CONFIG_SCSI_ZALON=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
-
-#
-# PCMCIA SCSI adapter support
-#
-# CONFIG_PCMCIA_AHA152X is not set
-# CONFIG_PCMCIA_FDOMAIN is not set
-# CONFIG_PCMCIA_NINJA_SCSI is not set
-# CONFIG_PCMCIA_QLOGIC is not set
-# CONFIG_PCMCIA_SYM53C500 is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_ATA is not set
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=y
 CONFIG_MD_RAID0=y
 CONFIG_MD_RAID1=y
 CONFIG_MD_RAID10=y
-CONFIG_MD_RAID5=y
-CONFIG_MD_RAID6=y
+# CONFIG_MD_RAID456 is not set
 # CONFIG_MD_MULTIPATH is not set
 # CONFIG_MD_FAULTY is not set
 CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
 # CONFIG_DM_CRYPT is not set
 # CONFIG_DM_SNAPSHOT is not set
 # CONFIG_DM_MIRROR is not set
 # CONFIG_DM_ZERO is not set
 # CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -499,35 +517,20 @@ CONFIG_BLK_DEV_DM=y
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_TUN=m
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
+# CONFIG_IP1000 is not set
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 CONFIG_LASI_82596=y
@@ -536,10 +539,6 @@ CONFIG_LASI_82596=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=y
@@ -554,6 +553,10 @@ CONFIG_TULIP=y
 # CONFIG_PCMCIA_XIRTULIP is not set
 # CONFIG_DEPCA is not set
 # CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
@@ -561,7 +564,6 @@ CONFIG_NET_PCI=y
 # CONFIG_AC3200 is not set
 # CONFIG_B44 is not set
 # CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 # CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
@@ -577,15 +579,14 @@ CONFIG_NET_PCI=y
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
 # CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 CONFIG_ACENIC=y
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
 # CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -597,64 +598,36 @@ CONFIG_ACENIC=y
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 # CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-# CONFIG_PCMCIA_WAVELAN is not set
-# CONFIG_PCMCIA_NETWAVE is not set
-
-#
-# Wireless 802.11 Frequency Hopping cards support
-#
-# CONFIG_PCMCIA_RAYCS is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-CONFIG_HERMES=y
-# CONFIG_PLX_HERMES is not set
-# CONFIG_TMD_HERMES is not set
-# CONFIG_NORTEL_HERMES is not set
-# CONFIG_PCI_HERMES is not set
-# CONFIG_ATMEL is not set
-
-#
-# Wireless 802.11b Pcmcia/Cardbus cards support
+# Wireless LAN
 #
-CONFIG_PCMCIA_HERMES=y
-CONFIG_PCMCIA_SPECTRUM=y
-# CONFIG_AIRO_CS is not set
-# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
-#
-# CONFIG_PRISM54 is not set
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# PCMCIA network device support
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
 CONFIG_NET_PCMCIA=y
 # CONFIG_PCMCIA_3C589 is not set
 # CONFIG_PCMCIA_3C574 is not set
@@ -664,10 +637,6 @@ CONFIG_NET_PCMCIA=y
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_PCMCIA_AXNET is not set
-
-#
-# Wan interfaces
-#
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -681,27 +650,23 @@ CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
 # CONFIG_PPP_MPPE is not set
 CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
 # CONFIG_SLIP is not set
+CONFIG_SLHC=m
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -726,14 +691,23 @@ CONFIG_KEYBOARD_ATKBD_HP_KEYCODES=y
 # CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
 # CONFIG_KEYBOARD_HIL_OLD is not set
 CONFIG_KEYBOARD_HIL=y
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 CONFIG_MOUSE_SERIAL=y
+# CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 CONFIG_MOUSE_HIL=y
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -757,6 +731,7 @@ CONFIG_SERIO_LIBPS2=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -764,6 +739,8 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_GSC=y
+CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_CS=y
 CONFIG_SERIAL_8250_NR_UARTS=17
 CONFIG_SERIAL_8250_RUNTIME_UARTS=4
@@ -788,25 +765,14 @@ CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 CONFIG_PPDEV=m
 # CONFIG_TIPAR is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
 CONFIG_GEN_RTC=y
 CONFIG_GEN_RTC_X=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
+# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
@@ -816,16 +782,8 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_CARDMAN_4000 is not set
 # CONFIG_CARDMAN_4040 is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -833,46 +791,59 @@ CONFIG_GEN_RTC_X=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
 
 #
-# Misc devices
+# Sonics Silicon Backplane
 #
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
-# Multimedia Capabilities Port drivers
+# Multifunction device drivers
 #
+# CONFIG_MFD_SM501 is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
 
 #
-# Digital Video Broadcasting Devices
+# Graphics support
 #
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Graphics support
+# Display device support
 #
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
 # CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
@@ -883,17 +854,20 @@ CONFIG_FB_STI=y
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON_OLD is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
 # CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -903,6 +877,7 @@ CONFIG_DUMMY_CONSOLE=y
 CONFIG_DUMMY_CONSOLE_COLUMNS=128
 CONFIG_DUMMY_CONSOLE_ROWS=48
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_STI_CONSOLE=y
 CONFIG_FONTS=y
@@ -916,16 +891,11 @@ CONFIG_FONT_8x16=y
 # CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_SUN12x22 is not set
 # CONFIG_FONT_10x18 is not set
-
-#
-# Logo configuration
-#
 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_PARISC_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -938,35 +908,36 @@ CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_TIMER=y
 CONFIG_SND_PCM=y
-CONFIG_SND_HWDEP=y
 CONFIG_SND_SEQUENCER=y
 # CONFIG_SND_SEQ_DUMMY is not set
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
 CONFIG_SND_SEQUENCER_OSS=y
 CONFIG_SND_DYNAMIC_MINORS=y
 CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
 #
 # Generic devices
 #
-CONFIG_SND_OPL3_LIB=y
 CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
+# CONFIG_SND_MTS64 is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
+# CONFIG_SND_PORTMAN2X4 is not set
 
 #
 # PCI devices
 #
 CONFIG_SND_AD1889=y
-CONFIG_SND_AD1889_OPL3=y
+# CONFIG_SND_ALS300 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -979,6 +950,18 @@ CONFIG_SND_AD1889_OPL3=y
 # CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS46XX is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_ENS1370 is not set
@@ -998,6 +981,7 @@ CONFIG_SND_AD1889_OPL3=y
 # CONFIG_SND_MIXART is not set
 # CONFIG_SND_NM256 is not set
 # CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
 # CONFIG_SND_RME32 is not set
 # CONFIG_SND_RME96 is not set
 # CONFIG_SND_RME9652 is not set
@@ -1007,31 +991,54 @@ CONFIG_SND_AD1889_OPL3=y
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
 # CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
 
 #
 # USB devices
 #
 # CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
 
 #
 # PCMCIA devices
 #
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
 
 #
 # GSC devices
 #
 CONFIG_SND_HARMONY=y
 
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# SoC Audio support for SuperH
+#
+
 #
 # Open Sound System
 #
 # CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
 
 #
-# USB support
+# USB Input Devices
 #
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -1039,7 +1046,7 @@ CONFIG_USB=y
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_OTG is not set
 
@@ -1049,15 +1056,16 @@ CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_EHCI_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
 #
-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 
@@ -1071,53 +1079,11 @@ CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_LIBUSUAL is not set
 
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=y
-CONFIG_USB_HIDINPUT=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-# CONFIG_USB_ZD1201 is not set
 CONFIG_USB_MON=y
 
 #
@@ -1135,16 +1101,22 @@ CONFIG_USB_MON=y
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
 # CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
 
 #
@@ -1155,20 +1127,29 @@ CONFIG_USB_MON=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_RTC_CLASS is not set
 
 #
-# MMC/SD Card support
+# DMA Engine support
 #
-# CONFIG_MMC is not set
+# CONFIG_DMA_ENGINE is not set
 
 #
-# InfiniBand support
+# DMA Clients
 #
-# CONFIG_INFINIBAND is not set
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# DMA Devices
+#
+# CONFIG_AUXDISPLAY is not set
+
+#
+# Userspace I/O
 #
+# CONFIG_UIO is not set
 
 #
 # File systems
@@ -1178,16 +1159,19 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=y
@@ -1217,11 +1201,12 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -1229,6 +1214,7 @@ CONFIG_RAMFS=y
 #
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
@@ -1261,6 +1247,7 @@ CONFIG_EXPORTFS=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
 CONFIG_RPCSEC_GSS_KRB5=y
 CONFIG_RPCSEC_GSS_SPKM3=m
 CONFIG_SMB_FS=m
@@ -1268,12 +1255,13 @@ CONFIG_SMB_NLS_DEFAULT=y
 CONFIG_SMB_NLS_REMOTE="cp437"
 CONFIG_CIFS=m
 # CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
 # CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
 # CONFIG_CIFS_EXPERIMENTAL is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1325,6 +1313,11 @@ CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=y
 
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
 #
 # Profiling support
 #
@@ -1335,21 +1328,32 @@ CONFIG_OPROFILE=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=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=y
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_RODATA is not set
 
 #
@@ -1358,12 +1362,13 @@ CONFIG_FORCED_INLINING=y
 CONFIG_KEYS=y
 CONFIG_KEYS_DEBUG_PROC_KEYS=y
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MD5=y
@@ -1372,9 +1377,18 @@ CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_TGR192=m
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_CAST5=m
@@ -1383,21 +1397,28 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_ANUBIS=m
+# CONFIG_CRYPTO_SEED is not set
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_CAMELLIA is not set
 CONFIG_CRYPTO_TEST=m
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_HW is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 0b9d5b1..38a1c1b 100644 (file)
@@ -20,7 +20,7 @@
        .import hpux_call_table
        .import hpux_syscall_exit,code
 
-       .align 4096
+       .align  PAGE_SIZE
 ENTRY(hpux_gateway_page)
        nop
 #ifdef CONFIG_64BIT
@@ -103,5 +103,5 @@ syscall_nosys:
        ldo     -ENOSYS(%r0),%r28
 ENDPROC(hpux_gateway_page)
 
-       .align 4096
+       .align  PAGE_SIZE
 ENTRY(end_hpux_gateway_page)
index d3b7917..eaa79bc 100644 (file)
@@ -290,9 +290,6 @@ int main(void)
        DEFINE(ASM_PTE_ENTRY_SIZE, PTE_ENTRY_SIZE);
        DEFINE(ASM_PFN_PTE_SHIFT, PFN_PTE_SHIFT);
        DEFINE(ASM_PT_INITIAL, PT_INITIAL);
-       DEFINE(ASM_PAGE_SIZE, PAGE_SIZE);
-       DEFINE(ASM_PAGE_SIZE_DIV64, PAGE_SIZE/64);
-       DEFINE(ASM_PAGE_SIZE_DIV128, PAGE_SIZE/128);
        BLANK();
        DEFINE(EXCDATA_IP, offsetof(struct exception_data, fault_ip));
        DEFINE(EXCDATA_SPACE, offsetof(struct exception_data, fault_space));
index 42598ab..111d472 100644 (file)
@@ -98,7 +98,6 @@
         * The "get_stack" macros are responsible for determining the
         * kernel stack value.
         *
-        * For Faults:
         *      If sr7 == 0
         *          Already using a kernel stack, so call the
         *          get_stack_use_r30 macro to push a pt_regs structure
         *          task pointer pointed to by cr30. Set the stack
         *          pointer to point to the end of the task structure.
         *
-        * For Interrupts:
-        *      If sr7 == 0
-        *          Already using a kernel stack, check to see if r30
-        *          is already pointing to the per processor interrupt
-        *          stack. If it is, call the get_stack_use_r30 macro
-        *          to push a pt_regs structure on the stack, and store
-        *          registers there. Otherwise, call get_stack_use_cr31
-        *          to get a pointer to the base of the interrupt stack
-        *          and push a pt_regs structure on that stack.
-        *      else
-        *          Need to set up a kernel stack, so call the
-        *          get_stack_use_cr30 macro to set up a pointer
-        *          to the pt_regs structure contained within the
-        *          task pointer pointed to by cr30. Set the stack
-        *          pointer to point to the end of the task structure.
-        *          N.B: We don't use the interrupt stack for the
-        *          first interrupt from userland, because signals/
-        *          resched's are processed when returning to userland,
-        *          and we can sleep in those cases.
-        *
         * Note that we use shadowed registers for temps until
         * we can save %r26 and %r29. %r26 is used to preserve
         * %r8 (a shadowed register) which temporarily contained
 
        .text
 
-       .align 4096
+       .align  PAGE_SIZE
 
 ENTRY(fault_vector_20)
        /* First vector is invalid (0) */
@@ -904,7 +883,7 @@ ENDPROC(_switch_to)
         *
         */
 
-       .align 4096
+       .align  PAGE_SIZE
 
 ENTRY(syscall_exit_rfi)
        mfctl   %cr30,%r16
@@ -1086,23 +1065,13 @@ intr_do_preempt:
 
 intr_extint:
        CMPIB=,n 0,%r16,1f
+
        get_stack_use_cr30
-       b,n 3f
+       b,n 2f
 
 1:
-#if 0  /* Interrupt Stack support not working yet! */
-       mfctl   %cr31,%r1
-       copy    %r30,%r17
-       /* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/
-       DEPI    0,31,15,%r17
-       CMPB=,n %r1,%r17,2f
-       get_stack_use_cr31
-       b,n 3f
-#endif
-2:
        get_stack_use_r30
-
-3:
+2:
        save_specials   %r29
        virt_map
        save_general    %r29
index 9676c48..a7b8859 100644 (file)
@@ -95,7 +95,7 @@ $bss_loop:
 
 1:
        stw             %r3,0(%r4)
-       ldo             (ASM_PAGE_SIZE >> PxD_VALUE_SHIFT)(%r3),%r3
+       ldo             (PAGE_SIZE >> PxD_VALUE_SHIFT)(%r3),%r3
        addib,>         -1,%r1,1b
 #if PT_NLEVELS == 3
        ldo             ASM_PMD_ENTRY_SIZE(%r4),%r4
@@ -128,10 +128,6 @@ $pgt_fill_loop:
        /* And the stack pointer too */
        ldo             THREAD_SZ_ALGN(%r6),%sp
 
-       /* And the interrupt stack */
-       load32          interrupt_stack,%r6
-       mtctl           %r6,%cr31
-
 #ifdef CONFIG_SMP
        /* Set the smp rendevous address into page zero.
        ** It would be safer to do this in init_smp_config() but
index 43b41df..2cbf13b 100644 (file)
         * IODC requires 7K byte stack.  That leaves 1K byte for os_hpmc.
         */
 
-       .align 4096
+       .align  PAGE_SIZE
 hpmc_stack:
        .block 16384
 
 #define HPMC_IODC_BUF_SIZE 0x8000
 
-       .align 4096
+       .align  PAGE_SIZE
 hpmc_iodc_buf:
        .block HPMC_IODC_BUF_SIZE
 
index 446f98d..26198a0 100644 (file)
@@ -49,7 +49,6 @@ EXPORT_SYMBOL(init_mm);
  * way process stacks are handled. This is done by having a special
  * "init_task" linker map entry..
  */
-unsigned char interrupt_stack[ISTACK_SIZE] __attribute__ ((section("init_istack"), aligned(4096)));
 union thread_union init_thread_union
        __attribute__((aligned(128))) __attribute__((__section__(".data.init_task"))) =
                { INIT_THREAD_INFO(init_task) };
index 90b2408..5901092 100644 (file)
@@ -289,7 +289,7 @@ ENTRY(copy_user_page_asm)
         */
 
        ldd             0(%r25), %r19
-       ldi             ASM_PAGE_SIZE_DIV128, %r1
+       ldi             (PAGE_SIZE / 128), %r1
 
        ldw             64(%r25), %r0           /* prefetch 1 cacheline ahead */
        ldw             128(%r25), %r0          /* prefetch 2 */
@@ -355,7 +355,7 @@ ENTRY(copy_user_page_asm)
         * use ldd/std on a 32 bit kernel.
         */
        ldw             0(%r25), %r19
-       ldi             ASM_PAGE_SIZE_DIV64, %r1
+       ldi             (PAGE_SIZE / 64), %r1
 
 1:
        ldw             4(%r25), %r20
@@ -553,7 +553,7 @@ ENTRY(__clear_user_page_asm)
        pdtlb           0(%r28)
 
 #ifdef CONFIG_64BIT
-       ldi             ASM_PAGE_SIZE_DIV128, %r1
+       ldi             (PAGE_SIZE / 128), %r1
 
        /* PREFETCH (Write) has not (yet) been proven to help here */
        /* #define      PREFETCHW_OP    ldd             256(%0), %r0 */
@@ -578,7 +578,7 @@ ENTRY(__clear_user_page_asm)
        ldo             128(%r28), %r28
 
 #else  /* ! CONFIG_64BIT */
-       ldi             ASM_PAGE_SIZE_DIV64, %r1
+       ldi             (PAGE_SIZE / 64), %r1
 
 1:
        stw             %r0, 0(%r28)
index 7aca704..671ee5b 100644 (file)
@@ -122,31 +122,9 @@ EXPORT_SYMBOL($$divI_12);
 EXPORT_SYMBOL($$divI_14);
 EXPORT_SYMBOL($$divI_15);
 
-extern void __ashrdi3(void);
-extern void __ashldi3(void);
-extern void __lshrdi3(void);
-extern void __muldi3(void);
-
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__muldi3);
-
 asmlinkage void * __canonicalize_funcptr_for_compare(void *);
 EXPORT_SYMBOL(__canonicalize_funcptr_for_compare);
 
-#ifdef CONFIG_64BIT
-extern void __divdi3(void);
-extern void __udivdi3(void);
-extern void __umoddi3(void);
-extern void __moddi3(void);
-
-EXPORT_SYMBOL(__divdi3);
-EXPORT_SYMBOL(__udivdi3);
-EXPORT_SYMBOL(__umoddi3);
-EXPORT_SYMBOL(__moddi3);
-#endif
-
 #ifndef CONFIG_64BIT
 extern void $$dyncall(void);
 EXPORT_SYMBOL($$dyncall);
index 23c1388..9448d4e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/scatterlist.h>
 
 #include <asm/cacheflush.h>
 #include <asm/dma.h>    /* for DMA_CHUNK_SIZE */
@@ -569,11 +570,10 @@ static void *fail_alloc_consistent(struct device *dev, size_t size,
 static void *pa11_dma_alloc_noncoherent(struct device *dev, size_t size,
                                          dma_addr_t *dma_handle, gfp_t flag)
 {
-       void *addr = NULL;
+       void *addr;
 
-       /* rely on kmalloc to be cacheline aligned */
-       addr = kmalloc(size, flag);
-       if(addr)
+       addr = (void *)__get_free_pages(flag, get_order(size));
+       if (addr)
                *dma_handle = (dma_addr_t)virt_to_phys(addr);
 
        return addr;
@@ -582,7 +582,7 @@ static void *pa11_dma_alloc_noncoherent(struct device *dev, size_t size,
 static void pa11_dma_free_noncoherent(struct device *dev, size_t size,
                                        void *vaddr, dma_addr_t iova)
 {
-       kfree(vaddr);
+       free_pages((unsigned long)vaddr, get_order(size));
        return;
 }
 
index 563df00..507d0ac 100644 (file)
@@ -194,37 +194,13 @@ void __init pcibios_init_bus(struct pci_bus *bus)
        pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl);
 }
 
-
-/* KLUGE: Link the child and parent resources - generic PCI didn't */
-static void
-pcibios_link_hba_resources( struct resource *hba_res, struct resource *r)
-{
-       if (!r->parent) {
-               printk(KERN_EMERG "PCI: resource not parented! [%p-%p]\n",
-                               (void*) r->start, (void*) r->end);
-               r->parent = hba_res;
-
-               /* reverse link is harder *sigh*  */
-               if (r->parent->child) {
-                       if (r->parent->sibling) {
-                               struct resource *next = r->parent->sibling;
-                               while (next->sibling)
-                                        next = next->sibling;
-                               next->sibling = r;
-                       } else {
-                               r->parent->sibling = r;
-                       }
-               } else
-                       r->parent->child = r;
-       }
-}
-
 /* called by drivers/pci/setup-bus.c:pci_setup_bridge().  */
 void __devinit pcibios_resource_to_bus(struct pci_dev *dev,
                struct pci_bus_region *region, struct resource *res)
 {
-       struct pci_bus *bus = dev->bus;
-       struct pci_hba_data *hba = HBA_DATA(bus->bridge->platform_data);
+#ifdef CONFIG_64BIT
+       struct pci_hba_data *hba = HBA_DATA(dev->bus->bridge->platform_data);
+#endif
 
        if (res->flags & IORESOURCE_IO) {
                /*
@@ -243,23 +219,15 @@ void __devinit pcibios_resource_to_bus(struct pci_dev *dev,
        }
 
        DBG_RES("pcibios_resource_to_bus(%02x %s [%lx,%lx])\n",
-               bus->number, res->flags & IORESOURCE_IO ? "IO" : "MEM",
+               dev->bus->number, res->flags & IORESOURCE_IO ? "IO" : "MEM",
                region->start, region->end);
-
-       /* KLUGE ALERT
-       ** if this resource isn't linked to a "parent", then it seems
-       ** to be a child of the HBA - lets link it in.
-       */
-       pcibios_link_hba_resources(&hba->io_space, bus->resource[0]);
-       pcibios_link_hba_resources(&hba->lmmio_space, bus->resource[1]);
 }
 
 void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
                              struct pci_bus_region *region)
 {
 #ifdef CONFIG_64BIT
-       struct pci_bus *bus = dev->bus;
-       struct pci_hba_data *hba = HBA_DATA(bus->bridge->platform_data);
+       struct pci_hba_data *hba = HBA_DATA(dev->bus->bridge->platform_data);
 #endif
 
        if (res->flags & IORESOURCE_MEM) {
index 549f548..370086f 100644 (file)
@@ -82,7 +82,12 @@ static int __cpuinit processor_probe(struct parisc_device *dev)
        unsigned long cpuid;
        struct cpuinfo_parisc *p;
 
-#ifndef CONFIG_SMP
+#ifdef CONFIG_SMP
+       if (num_online_cpus() >= NR_CPUS) {
+               printk(KERN_INFO "num_online_cpus() >= NR_CPUS\n");
+               return 1;
+       }
+#else
        if (boot_cpu_data.cpu_count > 0) {
                printk(KERN_INFO "CONFIG_SMP=n  ignoring additional CPUs\n");
                return 1;
index d7bc7bb..85fc775 100644 (file)
@@ -432,22 +432,10 @@ smp_cpu_init(int cpunum)
 void __init smp_callin(void)
 {
        int slave_id = cpu_now_booting;
-#if 0
-       void *istack;
-#endif
 
        smp_cpu_init(slave_id);
        preempt_disable();
 
-#if 0  /* NOT WORKING YET - see entry.S */
-       istack = (void *)__get_free_pages(GFP_KERNEL,ISTACK_ORDER);
-       if (istack == NULL) {
-           printk(KERN_CRIT "Failed to allocate interrupt stack for cpu %d\n",slave_id);
-           BUG();
-       }
-       mtctl(istack,31);
-#endif
-
        flush_cache_all_local(); /* start with known state */
        flush_tlb_all_local(NULL);
 
index 2989c66..50bbf33 100644 (file)
@@ -473,3 +473,10 @@ long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
        return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
                                  buf, len);
 }
+
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+                               u32 lenhi, u32 lenlo)
+{
+        return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+                             ((loff_t)lenhi << 32) | lenlo);
+}
index 56f6231..69b6eeb 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/unistd.h>
 #include <asm/errno.h>
+#include <asm/page.h>
 #include <asm/psw.h>
 #include <asm/thread_info.h>
 #include <asm/assembly.h>
@@ -38,7 +39,7 @@
         * pointers.
         */
 
-       .align ASM_PAGE_SIZE
+       .align PAGE_SIZE
 ENTRY(linux_gateway_page)
 
         /* ADDRESS 0x00 to 0xb0 = 176 bytes / 4 bytes per insn = 44 insns */
@@ -597,7 +598,7 @@ cas_action:
 
 
        /* Make sure nothing else is placed on this page */
-       .align ASM_PAGE_SIZE
+       .align PAGE_SIZE
 END(linux_gateway_page)
 ENTRY(end_linux_gateway_page)
 
@@ -608,7 +609,7 @@ ENTRY(end_linux_gateway_page)
 
        .section .rodata,"a"
 
-       .align ASM_PAGE_SIZE
+       .align PAGE_SIZE
        /* Light-weight-syscall table */
        /* Start of lws table. */
 ENTRY(lws_table)
@@ -617,13 +618,13 @@ ENTRY(lws_table)
 END(lws_table)
        /* End of lws table */
 
-       .align ASM_PAGE_SIZE
+       .align PAGE_SIZE
 ENTRY(sys_call_table)
 #include "syscall_table.S"
 END(sys_call_table)
 
 #ifdef CONFIG_64BIT
-       .align ASM_PAGE_SIZE
+       .align PAGE_SIZE
 ENTRY(sys_call_table64)
 #define SYSCALL_TABLE_64BIT
 #include "syscall_table.S"
@@ -636,7 +637,7 @@ END(sys_call_table64)
                will use this set of locks 
        */
        .section .data
-       .align 4096
+       .align  PAGE_SIZE
 ENTRY(lws_lock_start)
        /* lws locks */
        .align 16
index 2540786..117438e 100644 (file)
        ENTRY_COMP(signalfd)
        ENTRY_COMP(timerfd)
        ENTRY_SAME(eventfd)
+       ENTRY_COMP(fallocate)           /* 305 */
 
        /* Nothing yet */
 
index 8b3062a..24be86b 100644 (file)
@@ -189,16 +189,14 @@ static struct clocksource clocksource_cr16 = {
 #ifdef CONFIG_SMP
 int update_cr16_clocksource(void)
 {
-       int change = 0;
-
        /* since the cr16 cycle counters are not synchronized across CPUs,
           we'll check if we should switch to a safe clocksource: */
        if (clocksource_cr16.rating != 0 && num_online_cpus() > 1) {
                clocksource_change_rating(&clocksource_cr16, 0);
-               change = 1;
+               return 1;
        }
 
-       return change;
+       return 0;
 }
 #else
 int update_cr16_clocksource(void)
index cf780cb..701b2d2 100644 (file)
@@ -209,8 +209,8 @@ static int unwind_init(void)
 
 static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
 {
-       void handle_interruption(int, struct pt_regs *);
-       static unsigned long *hi = (unsigned long)&handle_interruption;
+       extern void handle_interruption(int, struct pt_regs *);
+       static unsigned long *hi = (unsigned long *)&handle_interruption;
 
        if (pc == get_func_addr(hi)) {
                struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
index ee7a16e..40d0ff9 100644 (file)
@@ -46,168 +46,211 @@ jiffies = jiffies_64;
 #endif
 SECTIONS
 {
+       . = KERNEL_BINARY_TEXT_START;
 
-  . = KERNEL_BINARY_TEXT_START;
-
-  _text = .;                   /* Text and read-only data */
-  .text ALIGN(16) : {
-       TEXT_TEXT
-       SCHED_TEXT
-       LOCK_TEXT
-       *(.text.do_softirq)
-       *(.text.sys_exit)
-       *(.text.do_sigaltstack)
-       *(.text.do_fork)
-       *(.text.*)
-       *(.fixup)
-       *(.lock.text)           /* out-of-line lock text */
-       *(.gnu.warning)
+       _text = .;              /* Text and read-only data */
+       .text ALIGN(16) : {
+               TEXT_TEXT
+               SCHED_TEXT
+               LOCK_TEXT
+               *(.text.do_softirq)
+               *(.text.sys_exit)
+               *(.text.do_sigaltstack)
+               *(.text.do_fork)
+               *(.text.*)
+               *(.fixup)
+               *(.lock.text)           /* out-of-line lock text */
+               *(.gnu.warning)
        } = 0
+       /* End of text section */
+       _etext = .;
 
-  _etext = .;                  /* End of text section */
+       RODATA
+       BUG_TABLE
 
-  RODATA
-
-  BUG_TABLE
-
-  /* writeable */
-  . = ALIGN(ASM_PAGE_SIZE);    /* Make sure this is page aligned so
-                                  that we can properly leave these
-                                  as writable */
-  data_start = .;
-
-  . = ALIGN(16);               /* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
+       /* writeable */
+       /* Make sure this is page aligned so
+        * that we can properly leave these
+        * as writable
+        */
+       . = ALIGN(PAGE_SIZE);
+       data_start = .;
+       . = ALIGN(16);
+       /* Exception table */
+       __ex_table : {
+               __start___ex_table = .;
+               *(__ex_table)
+               __stop___ex_table = .;
+       }
 
-  NOTES
+       NOTES
 
-  __start___unwind = .;         /* unwind info */
-  .PARISC.unwind : { *(.PARISC.unwind) }
-  __stop___unwind = .;
+       /* unwind info */
+       .PARISC.unwind : {
+               __start___unwind = .;
+               *(.PARISC.unwind)
+               __stop___unwind = .;
+       }
 
-  /* rarely changed data like cpu maps */
-  . = ALIGN(16);
-  .data.read_mostly : { *(.data.read_mostly) }
+       /* rarely changed data like cpu maps */
+       . = ALIGN(16);
+       .data.read_mostly : {
+               *(.data.read_mostly)
+       }
 
-  . = ALIGN(L1_CACHE_BYTES);
-  .data : {                    /* Data */
-       DATA_DATA
-       CONSTRUCTORS
+       . = ALIGN(L1_CACHE_BYTES);
+       /* Data */
+       .data : {
+               DATA_DATA
+               CONSTRUCTORS
        }
 
-  . = ALIGN(L1_CACHE_BYTES);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+       . = ALIGN(L1_CACHE_BYTES);
+       .data.cacheline_aligned : {
+               *(.data.cacheline_aligned)
+       }
 
-  /* PA-RISC locks requires 16-byte alignment */
-  . = ALIGN(16);
-  .data.lock_aligned : { *(.data.lock_aligned) }
+       /* PA-RISC locks requires 16-byte alignment */
+       . = ALIGN(16);
+       .data.lock_aligned : {
+               *(.data.lock_aligned)
+       }
 
-  . = ALIGN(ASM_PAGE_SIZE);
-  /* nosave data is really only used for software suspend...it's here
-   * just in case we ever implement it */
-  __nosave_begin = .;
-  .data_nosave : { *(.data.nosave) }
-  . = ALIGN(ASM_PAGE_SIZE);
-  __nosave_end = .;
+       /* nosave data is really only used for software suspend...it's here
+        * just in case we ever implement it
+        */
+       . = ALIGN(PAGE_SIZE);
+       __nosave_begin = .;
+       .data_nosave : {
+               *(.data.nosave)
+       }
+       . = ALIGN(PAGE_SIZE);
+       __nosave_end = .;
 
-  _edata = .;                  /* End of data section */
+       /* End of data section */
+       _edata = .;
 
-  __bss_start = .;             /* BSS */
-  /* page table entries need to be PAGE_SIZE aligned */
-  . = ALIGN(ASM_PAGE_SIZE);
-  .data.vmpages : {
-       *(.data.vm0.pmd)
-       *(.data.vm0.pgd)
-       *(.data.vm0.pte)
+       /* BSS */
+       __bss_start = .;
+       /* page table entries need to be PAGE_SIZE aligned */
+       . = ALIGN(PAGE_SIZE);
+       .data.vmpages : {
+               *(.data.vm0.pmd)
+               *(.data.vm0.pgd)
+               *(.data.vm0.pte)
        }
-  .bss : { *(.bss) *(COMMON) }
-  __bss_stop = .;
-
+       .bss : {
+               *(.bss)
+               *(COMMON)
+       }
+       __bss_stop = .;
 
-  /* assembler code expects init_task to be 16k aligned */
-  . = ALIGN(16384);            /* init_task */
-  .data.init_task : { *(.data.init_task) }
 
-  /* The interrupt stack is currently partially coded, but not yet
-   * implemented */
-  . = ALIGN(16384);    
-  init_istack : { *(init_istack) }
+       /* assembler code expects init_task to be 16k aligned */
+       . = ALIGN(16384);
+       /* init_task */
+       .data.init_task : {
+               *(.data.init_task)
+       }
 
 #ifdef CONFIG_64BIT
-  . = ALIGN(16);               /* Linkage tables */
-  .opd : { *(.opd) } PROVIDE (__gp = .); 
-  .plt : { *(.plt) } 
-  .dlt : { *(.dlt) }
+       . = ALIGN(16);
+       /* Linkage tables */
+       .opd : {
+               *(.opd)
+       } PROVIDE (__gp = .); 
+       .plt : {
+               *(.plt)
+       } 
+       .dlt : {
+               *(.dlt)
+       }
 #endif
 
-  /* reserve space for interrupt stack by aligning __init* to 16k */
-  . = ALIGN(16384);
-  __init_begin = .;
-  .init.text : { 
-       _sinittext = .;
-       *(.init.text)
-       _einittext = .;
-  }
-  .init.data : { *(.init.data) }
-  . = ALIGN(16);
-  __setup_start = .;
-  .init.setup : { *(.init.setup) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : {
-       INITCALLS
-  }
-  __initcall_end = .;
-  __con_initcall_start = .;
-  .con_initcall.init : { *(.con_initcall.init) }
-  __con_initcall_end = .;
-  SECURITY_INIT
-  /* alternate instruction replacement.  This is a mechanism x86 uses
-   * to detect the CPU type and replace generic instruction sequences
-   * with CPU specific ones.  We don't currently do this in PA, but
-   * it seems like a good idea... */
-  . = ALIGN(4);
-  __alt_instructions = .;
-  .altinstructions : { *(.altinstructions) } 
-  __alt_instructions_end = .; 
- .altinstr_replacement : { *(.altinstr_replacement) } 
-  /* .exit.text is discard at runtime, not link time, to deal with references
-     from .altinstructions and .eh_frame */
-  .exit.text : { *(.exit.text) }
-  .exit.data : { *(.exit.data) }
+       /* reserve space for interrupt stack by aligning __init* to 16k */
+       . = ALIGN(16384);
+       __init_begin = .;
+       .init.text : { 
+               _sinittext = .;
+               *(.init.text)
+               _einittext = .;
+       }
+       .init.data : {
+               *(.init.data)
+       }
+       . = ALIGN(16);
+       .init.setup : {
+               __setup_start = .;
+               *(.init.setup)
+               __setup_end = .;
+       }
+       .initcall.init : {
+               __initcall_start = .;
+               INITCALLS
+               __initcall_end = .;
+       }
+       .con_initcall.init : {
+               __con_initcall_start = .;
+               *(.con_initcall.init)
+               __con_initcall_end = .;
+       }
+       SECURITY_INIT
+
+       /* alternate instruction replacement.  This is a mechanism x86 uses
+        * to detect the CPU type and replace generic instruction sequences
+        * with CPU specific ones.  We don't currently do this in PA, but
+        * it seems like a good idea...
+        */
+       . = ALIGN(4);
+       .altinstructions : {
+               __alt_instructions = .;
+               *(.altinstructions)
+               __alt_instructions_end = .; 
+       } 
+       .altinstr_replacement : {
+               *(.altinstr_replacement)
+       } 
+
+       /* .exit.text is discard at runtime, not link time, to deal with references
+        *  from .altinstructions and .eh_frame
+        */
+       .exit.text : {
+               *(.exit.text)
+       }
+       .exit.data : {
+               *(.exit.data)
+       }
 #ifdef CONFIG_BLK_DEV_INITRD
-  . = ALIGN(ASM_PAGE_SIZE);
-  __initramfs_start = .;
-  .init.ramfs : { *(.init.ramfs) }
-  __initramfs_end = .;
+       . = ALIGN(PAGE_SIZE);
+       .init.ramfs : {
+               __initramfs_start = .;
+               *(.init.ramfs)
+               __initramfs_end = .;
+       }
 #endif
 
-  PERCPU(ASM_PAGE_SIZE)
+       PERCPU(PAGE_SIZE)
+       . = ALIGN(PAGE_SIZE);
+       __init_end = .;
+       /* freed after init ends here */
+       _end = . ;
 
-  . = ALIGN(ASM_PAGE_SIZE);
-  __init_end = .;
-  /* freed after init ends here */
-       
-  _end = . ;
-
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       *(.exitcall.exit)
+       /* Sections to be discarded */
+       /DISCARD/ : {
+               *(.exitcall.exit)
 #ifdef CONFIG_64BIT
-       /* temporary hack until binutils is fixed to not emit these
-        for static binaries */
-       *(.interp)
-       *(.dynsym)
-       *(.dynstr)
-       *(.dynamic)
-       *(.hash)
-       *(.gnu.hash)
+               /* temporary hack until binutils is fixed to not emit these
+                * for static binaries
+                */
+               *(.interp)
+               *(.dynsym)
+               *(.dynstr)
+               *(.dynamic)
+               *(.hash)
+               *(.gnu.hash)
 #endif
        }
 
-  STABS_DEBUG
-  .note 0 : { *(.note) }       
-
+       STABS_DEBUG
+       .note 0 : { *(.note) }  
 }
index 5f2e690..7ce406c 100644 (file)
@@ -4,4 +4,4 @@
 
 lib-y  := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o memcpy.o
 
-obj-y  := iomap.o
+obj-y  := libgcc/ milli/ iomap.o
diff --git a/arch/parisc/lib/libgcc/Makefile b/arch/parisc/lib/libgcc/Makefile
new file mode 100644 (file)
index 0000000..b67a85a
--- /dev/null
@@ -0,0 +1,4 @@
+obj-y  := __ashldi3.o __ashrdi3.o __clzsi2.o __divdi3.o __divsi3.o     \
+               __lshrdi3.o __moddi3.o __modsi3.o __udivdi3.o           \
+               __udivmoddi4.o __udivmodsi4.o __udivsi3.o               \
+               __umoddi3.o __umodsi3.o __muldi3.o __umulsidi3.o
diff --git a/arch/parisc/lib/libgcc/__ashldi3.c b/arch/parisc/lib/libgcc/__ashldi3.c
new file mode 100644 (file)
index 0000000..a14a257
--- /dev/null
@@ -0,0 +1,19 @@
+#include "libgcc.h"
+
+u64 __ashldi3(u64 v, int cnt)
+{
+       int c = cnt & 31;
+       u32 vl = (u32) v;
+       u32 vh = (u32) (v >> 32);
+
+       if (cnt & 32) {
+               vh = (vl << c);
+               vl = 0;
+       } else {
+               vh = (vh << c) + (vl >> (32 - c));
+               vl = (vl << c);
+       }
+
+       return ((u64) vh << 32) + vl;
+}
+EXPORT_SYMBOL(__ashldi3);
diff --git a/arch/parisc/lib/libgcc/__ashrdi3.c b/arch/parisc/lib/libgcc/__ashrdi3.c
new file mode 100644 (file)
index 0000000..8636a5a
--- /dev/null
@@ -0,0 +1,19 @@
+#include "libgcc.h"
+
+u64 __ashrdi3(u64 v, int cnt)
+{
+       int c = cnt & 31;
+       u32 vl = (u32) v;
+       u32 vh = (u32) (v >> 32);
+
+       if (cnt & 32) {
+               vl = ((s32) vh >> c);
+               vh = (s32) vh >> 31;
+       } else {
+               vl = (vl >> c) + (vh << (32 - c));
+               vh = ((s32) vh >> c);
+       }
+
+       return ((u64) vh << 32) + vl;
+}
+EXPORT_SYMBOL(__ashrdi3);
diff --git a/arch/parisc/lib/libgcc/__clzsi2.c b/arch/parisc/lib/libgcc/__clzsi2.c
new file mode 100644 (file)
index 0000000..a7aa2f5
--- /dev/null
@@ -0,0 +1,30 @@
+#include "libgcc.h"
+
+u32 __clzsi2(u32 v)
+{
+       int p = 31;
+
+       if (v & 0xffff0000) {
+               p -= 16;
+               v >>= 16;
+       }
+       if (v & 0xff00) {
+               p -= 8;
+               v >>= 8;
+       }
+       if (v & 0xf0) {
+               p -= 4;
+               v >>= 4;
+       }
+       if (v & 0xc) {
+               p -= 2;
+               v >>= 2;
+       }
+       if (v & 0x2) {
+               p -= 1;
+               v >>= 1;
+       }
+
+       return p;
+}
+EXPORT_SYMBOL(__clzsi2);
diff --git a/arch/parisc/lib/libgcc/__divdi3.c b/arch/parisc/lib/libgcc/__divdi3.c
new file mode 100644 (file)
index 0000000..f23c6fe
--- /dev/null
@@ -0,0 +1,23 @@
+#include "libgcc.h"
+
+s64 __divdi3(s64 num, s64 den)
+{
+       int minus = 0;
+       s64 v;
+
+       if (num < 0) {
+               num = -num;
+               minus = 1;
+       }
+       if (den < 0) {
+               den = -den;
+               minus ^= 1;
+       }
+
+       v = __udivmoddi4(num, den, NULL);
+       if (minus)
+               v = -v;
+
+       return v;
+}
+EXPORT_SYMBOL(__divdi3);
diff --git a/arch/parisc/lib/libgcc/__divsi3.c b/arch/parisc/lib/libgcc/__divsi3.c
new file mode 100644 (file)
index 0000000..730fb53
--- /dev/null
@@ -0,0 +1,23 @@
+#include "libgcc.h"
+
+s32 __divsi3(s32 num, s32 den)
+{
+       int minus = 0;
+       s32 v;
+
+       if (num < 0) {
+               num = -num;
+               minus = 1;
+       }
+       if (den < 0) {
+               den = -den;
+               minus ^= 1;
+       }
+
+       v = __udivmodsi4(num, den, NULL);
+       if (minus)
+               v = -v;
+
+       return v;
+}
+EXPORT_SYMBOL(__divsi3);
diff --git a/arch/parisc/lib/libgcc/__lshrdi3.c b/arch/parisc/lib/libgcc/__lshrdi3.c
new file mode 100644 (file)
index 0000000..4a82070
--- /dev/null
@@ -0,0 +1,19 @@
+#include "libgcc.h"
+
+u64 __lshrdi3(u64 v, int cnt)
+{
+       int c = cnt & 31;
+       u32 vl = (u32) v;
+       u32 vh = (u32) (v >> 32);
+
+       if (cnt & 32) {
+               vl = (vh >> c);
+               vh = 0;
+       } else {
+               vl = (vl >> c) + (vh << (32 - c));
+               vh = (vh >> c);
+       }
+
+       return ((u64) vh << 32) + vl;
+}
+EXPORT_SYMBOL(__lshrdi3);
diff --git a/arch/parisc/lib/libgcc/__moddi3.c b/arch/parisc/lib/libgcc/__moddi3.c
new file mode 100644 (file)
index 0000000..ed64bba
--- /dev/null
@@ -0,0 +1,23 @@
+#include "libgcc.h"
+
+s64 __moddi3(s64 num, s64 den)
+{
+       int minus = 0;
+       s64 v;
+
+       if (num < 0) {
+               num = -num;
+               minus = 1;
+       }
+       if (den < 0) {
+               den = -den;
+               minus ^= 1;
+       }
+
+       (void)__udivmoddi4(num, den, (u64 *) & v);
+       if (minus)
+               v = -v;
+
+       return v;
+}
+EXPORT_SYMBOL(__moddi3);
diff --git a/arch/parisc/lib/libgcc/__modsi3.c b/arch/parisc/lib/libgcc/__modsi3.c
new file mode 100644 (file)
index 0000000..62f773e
--- /dev/null
@@ -0,0 +1,23 @@
+#include "libgcc.h"
+
+s32 __modsi3(s32 num, s32 den)
+{
+       int minus = 0;
+       s32 v;
+
+       if (num < 0) {
+               num = -num;
+               minus = 1;
+       }
+       if (den < 0) {
+               den = -den;
+               minus ^= 1;
+       }
+
+       (void)__udivmodsi4(num, den, (u32 *) & v);
+       if (minus)
+               v = -v;
+
+       return v;
+}
+EXPORT_SYMBOL(__modsi3);
diff --git a/arch/parisc/lib/libgcc/__muldi3.c b/arch/parisc/lib/libgcc/__muldi3.c
new file mode 100644 (file)
index 0000000..3308abd
--- /dev/null
@@ -0,0 +1,22 @@
+#include "libgcc.h"
+
+union DWunion {
+       struct {
+               s32 high;
+               s32 low;
+       } s;
+       s64 ll;
+};
+
+s64 __muldi3(s64 u, s64 v)
+{
+       const union DWunion uu = { .ll = u };
+       const union DWunion vv = { .ll = v };
+       union DWunion w = { .ll = __umulsidi3(uu.s.low, vv.s.low) };
+
+       w.s.high += ((u32)uu.s.low * (u32)vv.s.high
+               + (u32)uu.s.high * (u32)vv.s.low);
+
+       return w.ll;
+}
+EXPORT_SYMBOL(__muldi3);
diff --git a/arch/parisc/lib/libgcc/__udivdi3.c b/arch/parisc/lib/libgcc/__udivdi3.c
new file mode 100644 (file)
index 0000000..740023d
--- /dev/null
@@ -0,0 +1,7 @@
+#include "libgcc.h"
+
+u64 __udivdi3(u64 num, u64 den)
+{
+       return __udivmoddi4(num, den, NULL);
+}
+EXPORT_SYMBOL(__udivdi3);
diff --git a/arch/parisc/lib/libgcc/__udivmoddi4.c b/arch/parisc/lib/libgcc/__udivmoddi4.c
new file mode 100644 (file)
index 0000000..2df0caa
--- /dev/null
@@ -0,0 +1,31 @@
+#include "libgcc.h"
+
+u64 __udivmoddi4(u64 num, u64 den, u64 * rem_p)
+{
+       u64 quot = 0, qbit = 1;
+
+       if (den == 0) {
+               BUG();
+       }
+
+       /* Left-justify denominator and count shift */
+       while ((s64) den >= 0) {
+               den <<= 1;
+               qbit <<= 1;
+       }
+
+       while (qbit) {
+               if (den <= num) {
+                       num -= den;
+                       quot += qbit;
+               }
+               den >>= 1;
+               qbit >>= 1;
+       }
+
+       if (rem_p)
+               *rem_p = num;
+
+       return quot;
+}
+EXPORT_SYMBOL(__udivmoddi4);
diff --git a/arch/parisc/lib/libgcc/__udivmodsi4.c b/arch/parisc/lib/libgcc/__udivmodsi4.c
new file mode 100644 (file)
index 0000000..2a2fc28
--- /dev/null
@@ -0,0 +1,31 @@
+#include "libgcc.h"
+
+u32 __udivmodsi4(u32 num, u32 den, u32 * rem_p)
+{
+       u32 quot = 0, qbit = 1;
+
+       if (den == 0) {
+               BUG();
+       }
+
+       /* Left-justify denominator and count shift */
+       while ((s32) den >= 0) {
+               den <<= 1;
+               qbit <<= 1;
+       }
+
+       while (qbit) {
+               if (den <= num) {
+                       num -= den;
+                       quot += qbit;
+               }
+               den >>= 1;
+               qbit >>= 1;
+       }
+
+       if (rem_p)
+               *rem_p = num;
+
+       return quot;
+}
+EXPORT_SYMBOL(__udivmodsi4);
diff --git a/arch/parisc/lib/libgcc/__udivsi3.c b/arch/parisc/lib/libgcc/__udivsi3.c
new file mode 100644 (file)
index 0000000..756a441
--- /dev/null
@@ -0,0 +1,7 @@
+#include "libgcc.h"
+
+u32 __udivsi3(u32 num, u32 den)
+{
+       return __udivmodsi4(num, den, NULL);
+}
+EXPORT_SYMBOL(__udivsi3);
diff --git a/arch/parisc/lib/libgcc/__umoddi3.c b/arch/parisc/lib/libgcc/__umoddi3.c
new file mode 100644 (file)
index 0000000..ac744e9
--- /dev/null
@@ -0,0 +1,10 @@
+#include "libgcc.h"
+
+u64 __umoddi3(u64 num, u64 den)
+{
+       u64 v;
+
+       (void)__udivmoddi4(num, den, &v);
+       return v;
+}
+EXPORT_SYMBOL(__umoddi3);
diff --git a/arch/parisc/lib/libgcc/__umodsi3.c b/arch/parisc/lib/libgcc/__umodsi3.c
new file mode 100644 (file)
index 0000000..51f55aa
--- /dev/null
@@ -0,0 +1,10 @@
+#include "libgcc.h"
+
+u32 __umodsi3(u32 num, u32 den)
+{
+       u32 v;
+
+       (void)__udivmodsi4(num, den, &v);
+       return v;
+}
+EXPORT_SYMBOL(__umodsi3);
diff --git a/arch/parisc/lib/libgcc/__umulsidi3.c b/arch/parisc/lib/libgcc/__umulsidi3.c
new file mode 100644 (file)
index 0000000..396f669
--- /dev/null
@@ -0,0 +1,46 @@
+#include "libgcc.h"
+
+#define __ll_B ((u32) 1 << (32 / 2))
+#define __ll_lowpart(t) ((u32) (t) & (__ll_B - 1))
+#define __ll_highpart(t) ((u32) (t) >> 16)
+
+#define umul_ppmm(w1, w0, u, v)                                                \
+  do {                                                                 \
+    u32 __x0, __x1, __x2, __x3;                                                \
+    u16 __ul, __vl, __uh, __vh;                                                \
+                                                                       \
+    __ul = __ll_lowpart (u);                                           \
+    __uh = __ll_highpart (u);                                          \
+    __vl = __ll_lowpart (v);                                           \
+    __vh = __ll_highpart (v);                                          \
+                                                                       \
+    __x0 = (u32) __ul * __vl;                                          \
+    __x1 = (u32) __ul * __vh;                                          \
+    __x2 = (u32) __uh * __vl;                                          \
+    __x3 = (u32) __uh * __vh;                                          \
+                                                                       \
+    __x1 += __ll_highpart (__x0);/* this can't give carry */           \
+    __x1 += __x2;               /* but this indeed can */              \
+    if (__x1 < __x2)            /* did we get it? */                   \
+      __x3 += __ll_B;           /* yes, add it in the proper pos.  */  \
+                                                                       \
+    (w1) = __x3 + __ll_highpart (__x1);                                        \
+    (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0);         \
+  } while (0)
+
+union DWunion {
+       struct {
+               s32 high;
+               s32 low;
+       } s;
+       s64 ll;
+};
+
+u64 __umulsidi3(u32 u, u32 v)
+{
+       union DWunion __w;
+
+       umul_ppmm(__w.s.high, __w.s.low, u, v);
+
+       return __w.ll;
+}
diff --git a/arch/parisc/lib/libgcc/libgcc.h b/arch/parisc/lib/libgcc/libgcc.h
new file mode 100644 (file)
index 0000000..5a6f7a5
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _PA_LIBGCC_H_
+#define _PA_LIBGCC_H_
+
+#include <linux/types.h>
+#include <linux/module.h>
+
+/* Cribbed from klibc/libgcc/ */
+u64 __ashldi3(u64 v, int cnt);
+u64 __ashrdi3(u64 v, int cnt);
+
+u32 __clzsi2(u32 v);
+
+s64 __divdi3(s64 num, s64 den);
+s32 __divsi3(s32 num, s32 den);
+
+u64 __lshrdi3(u64 v, int cnt);
+
+s64 __moddi3(s64 num, s64 den);
+s32 __modsi3(s32 num, s32 den);
+
+u64 __udivdi3(u64 num, u64 den);
+u32 __udivsi3(u32 num, u32 den);
+
+u64 __udivmoddi4(u64 num, u64 den, u64 * rem_p);
+u32 __udivmodsi4(u32 num, u32 den, u32 * rem_p);
+
+u64 __umulsidi3(u32 u, u32 v);
+
+u64 __umoddi3(u64 num, u64 den);
+u32 __umodsi3(u32 num, u32 den);
+
+#endif /*_PA_LIBGCC_H_*/
index 2c43ebe..d22042d 100644 (file)
@@ -139,12 +139,12 @@ DECLARE_PER_CPU(struct exception_data, exception_data);
 #define stw(_s,_t,_o,_a,_e)    def_store_insn(stw,"r",_s,_t,_o,_a,_e)
 
 #ifdef  CONFIG_PREFETCH
-extern inline void prefetch_src(const void *addr)
+static inline void prefetch_src(const void *addr)
 {
        __asm__("ldw 0(" s_space ",%0), %%r0" : : "r" (addr));
 }
 
-extern inline void prefetch_dst(const void *addr)
+static inline void prefetch_dst(const void *addr)
 {
        __asm__("ldd 0(" d_space ",%0), %%r0" : : "r" (addr));
 }
diff --git a/arch/parisc/lib/milli/Makefile b/arch/parisc/lib/milli/Makefile
new file mode 100644 (file)
index 0000000..9b24e9b
--- /dev/null
@@ -0,0 +1 @@
+obj-y  := dyncall.o divI.o divU.o remI.o remU.o div_const.o mulI.o
diff --git a/arch/parisc/lib/milli/divI.S b/arch/parisc/lib/milli/divI.S
new file mode 100644 (file)
index 0000000..ac106b7
--- /dev/null
@@ -0,0 +1,254 @@
+/* 32 and 64-bit millicode, original author Hewlett-Packard
+   adapted for gcc by Paul Bame <bame@debian.org>
+   and Alan Modra <alan@linuxcare.com.au>.
+
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This file is part of GCC and is released under the terms of
+   of the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+   See the file COPYING in the top-level GCC source directory for a copy
+   of the license.  */
+
+#include "milli.h"
+
+#ifdef L_divI
+/* ROUTINES:   $$divI, $$divoI
+
+   Single precision divide for signed binary integers.
+
+   The quotient is truncated towards zero.
+   The sign of the quotient is the XOR of the signs of the dividend and
+   divisor.
+   Divide by zero is trapped.
+   Divide of -2**31 by -1 is trapped for $$divoI but not for $$divI.
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   arg1 == divisor
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 =  undefined
+   .   arg1 =  undefined
+   .   ret1 =  quotient
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   =  undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions:
+   .           divisor is zero  (traps with ADDIT,=  0,25,0)
+   .           dividend==-2**31  and divisor==-1 and routine is $$divoI
+   .                            (traps with ADDO  26,25,0)
+   .   Changes memory at the following places:
+   .           NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable.
+   .   Suitable for internal or external millicode.
+   .   Assumes the special millicode register conventions.
+
+   DISCUSSION:
+   .   Branchs to other millicode routines using BE
+   .           $$div_# for # being 2,3,4,5,6,7,8,9,10,12,14,15
+   .
+   .   For selected divisors, calls a divide by constant routine written by
+   .   Karl Pettis.  Eligible divisors are 1..15 excluding 11 and 13.
+   .
+   .   The only overflow case is -2**31 divided by -1.
+   .   Both routines return -2**31 but only $$divoI traps.  */
+
+RDEFINE(temp,r1)
+RDEFINE(retreg,ret1)   /*  r29 */
+RDEFINE(temp1,arg0)
+       SUBSPA_MILLI_DIV
+       ATTR_MILLI
+       .import $$divI_2,millicode
+       .import $$divI_3,millicode
+       .import $$divI_4,millicode
+       .import $$divI_5,millicode
+       .import $$divI_6,millicode
+       .import $$divI_7,millicode
+       .import $$divI_8,millicode
+       .import $$divI_9,millicode
+       .import $$divI_10,millicode
+       .import $$divI_12,millicode
+       .import $$divI_14,millicode
+       .import $$divI_15,millicode
+       .export $$divI,millicode
+       .export $$divoI,millicode
+       .proc
+       .callinfo       millicode
+       .entry
+GSYM($$divoI)
+       comib,=,n  -1,arg1,LREF(negative1)      /*  when divisor == -1 */
+GSYM($$divI)
+       ldo     -1(arg1),temp           /*  is there at most one bit set ? */
+       and,<>  arg1,temp,r0            /*  if not, don't use power of 2 divide */
+       addi,>  0,arg1,r0               /*  if divisor > 0, use power of 2 divide */
+       b,n     LREF(neg_denom)
+LSYM(pow2)
+       addi,>= 0,arg0,retreg           /*  if numerator is negative, add the */
+       add     arg0,temp,retreg        /*  (denominaotr -1) to correct for shifts */
+       extru,= arg1,15,16,temp         /*  test denominator with 0xffff0000 */
+       extrs   retreg,15,16,retreg     /*  retreg = retreg >> 16 */
+       or      arg1,temp,arg1          /*  arg1 = arg1 | (arg1 >> 16) */
+       ldi     0xcc,temp1              /*  setup 0xcc in temp1 */
+       extru,= arg1,23,8,temp          /*  test denominator with 0xff00 */
+       extrs   retreg,23,24,retreg     /*  retreg = retreg >> 8 */
+       or      arg1,temp,arg1          /*  arg1 = arg1 | (arg1 >> 8) */
+       ldi     0xaa,temp               /*  setup 0xaa in temp */
+       extru,= arg1,27,4,r0            /*  test denominator with 0xf0 */
+       extrs   retreg,27,28,retreg     /*  retreg = retreg >> 4 */
+       and,=   arg1,temp1,r0           /*  test denominator with 0xcc */
+       extrs   retreg,29,30,retreg     /*  retreg = retreg >> 2 */
+       and,=   arg1,temp,r0            /*  test denominator with 0xaa */
+       extrs   retreg,30,31,retreg     /*  retreg = retreg >> 1 */
+       MILLIRETN
+LSYM(neg_denom)
+       addi,<  0,arg1,r0               /*  if arg1 >= 0, it's not power of 2 */
+       b,n     LREF(regular_seq)
+       sub     r0,arg1,temp            /*  make denominator positive */
+       comb,=,n  arg1,temp,LREF(regular_seq)   /*  test against 0x80000000 and 0 */
+       ldo     -1(temp),retreg         /*  is there at most one bit set ? */
+       and,=   temp,retreg,r0          /*  if so, the denominator is power of 2 */
+       b,n     LREF(regular_seq)
+       sub     r0,arg0,retreg          /*  negate numerator */
+       comb,=,n arg0,retreg,LREF(regular_seq) /*  test against 0x80000000 */
+       copy    retreg,arg0             /*  set up arg0, arg1 and temp  */
+       copy    temp,arg1               /*  before branching to pow2 */
+       b       LREF(pow2)
+       ldo     -1(arg1),temp
+LSYM(regular_seq)
+       comib,>>=,n 15,arg1,LREF(small_divisor)
+       add,>=  0,arg0,retreg           /*  move dividend, if retreg < 0, */
+LSYM(normal)
+       subi    0,retreg,retreg         /*    make it positive */
+       sub     0,arg1,temp             /*  clear carry,  */
+                                       /*    negate the divisor */
+       ds      0,temp,0                /*  set V-bit to the comple- */
+                                       /*    ment of the divisor sign */
+       add     retreg,retreg,retreg    /*  shift msb bit into carry */
+       ds      r0,arg1,temp            /*  1st divide step, if no carry */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  2nd divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  3rd divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  4th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  5th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  6th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  7th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  8th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  9th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  10th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  11th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  12th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  13th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  14th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  15th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  16th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  17th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  18th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  19th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  20th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  21st divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  22nd divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  23rd divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  24th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  25th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  26th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  27th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  28th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  29th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  30th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  31st divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  32nd divide step, */
+       addc    retreg,retreg,retreg    /*  shift last retreg bit into retreg */
+       xor,>=  arg0,arg1,0             /*  get correct sign of quotient */
+         sub   0,retreg,retreg         /*    based on operand signs */
+       MILLIRETN
+       nop
+
+LSYM(small_divisor)
+
+#if defined(CONFIG_64BIT)
+/*  Clear the upper 32 bits of the arg1 register.  We are working with */
+/*  small divisors (and 32-bit integers)   We must not be mislead  */
+/*  by "1" bits left in the upper 32 bits.  */
+       depd %r0,31,32,%r25
+#endif
+       blr,n   arg1,r0
+       nop
+/*  table for divisor == 0,1, ... ,15 */
+       addit,= 0,arg1,r0       /*  trap if divisor == 0 */
+       nop
+       MILLIRET                /*  divisor == 1 */
+       copy    arg0,retreg
+       MILLI_BEN($$divI_2)     /*  divisor == 2 */
+       nop
+       MILLI_BEN($$divI_3)     /*  divisor == 3 */
+       nop
+       MILLI_BEN($$divI_4)     /*  divisor == 4 */
+       nop
+       MILLI_BEN($$divI_5)     /*  divisor == 5 */
+       nop
+       MILLI_BEN($$divI_6)     /*  divisor == 6 */
+       nop
+       MILLI_BEN($$divI_7)     /*  divisor == 7 */
+       nop
+       MILLI_BEN($$divI_8)     /*  divisor == 8 */
+       nop
+       MILLI_BEN($$divI_9)     /*  divisor == 9 */
+       nop
+       MILLI_BEN($$divI_10)    /*  divisor == 10 */
+       nop
+       b       LREF(normal)            /*  divisor == 11 */
+       add,>=  0,arg0,retreg
+       MILLI_BEN($$divI_12)    /*  divisor == 12 */
+       nop
+       b       LREF(normal)            /*  divisor == 13 */
+       add,>=  0,arg0,retreg
+       MILLI_BEN($$divI_14)    /*  divisor == 14 */
+       nop
+       MILLI_BEN($$divI_15)    /*  divisor == 15 */
+       nop
+
+LSYM(negative1)
+       sub     0,arg0,retreg   /*  result is negation of dividend */
+       MILLIRET
+       addo    arg0,arg1,r0    /*  trap iff dividend==0x80000000 && divisor==-1 */
+       .exit
+       .procend
+       .end
+#endif
diff --git a/arch/parisc/lib/milli/divU.S b/arch/parisc/lib/milli/divU.S
new file mode 100644 (file)
index 0000000..9287fe2
--- /dev/null
@@ -0,0 +1,235 @@
+/* 32 and 64-bit millicode, original author Hewlett-Packard
+   adapted for gcc by Paul Bame <bame@debian.org>
+   and Alan Modra <alan@linuxcare.com.au>.
+
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This file is part of GCC and is released under the terms of
+   of the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+   See the file COPYING in the top-level GCC source directory for a copy
+   of the license.  */
+
+#include "milli.h"
+
+#ifdef L_divU
+/* ROUTINE:    $$divU
+   .
+   .   Single precision divide for unsigned integers.
+   .
+   .   Quotient is truncated towards zero.
+   .   Traps on divide by zero.
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   arg1 == divisor
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 =  undefined
+   .   arg1 =  undefined
+   .   ret1 =  quotient
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   =  undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions:
+   .           divisor is zero
+   .   Changes memory at the following places:
+   .           NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable.
+   .   Does not create a stack frame.
+   .   Suitable for internal or external millicode.
+   .   Assumes the special millicode register conventions.
+
+   DISCUSSION:
+   .   Branchs to other millicode routines using BE:
+   .           $$divU_# for 3,5,6,7,9,10,12,14,15
+   .
+   .   For selected small divisors calls the special divide by constant
+   .   routines written by Karl Pettis.  These are: 3,5,6,7,9,10,12,14,15.  */
+
+RDEFINE(temp,r1)
+RDEFINE(retreg,ret1)   /* r29 */
+RDEFINE(temp1,arg0)
+       SUBSPA_MILLI_DIV
+       ATTR_MILLI
+       .export $$divU,millicode
+       .import $$divU_3,millicode
+       .import $$divU_5,millicode
+       .import $$divU_6,millicode
+       .import $$divU_7,millicode
+       .import $$divU_9,millicode
+       .import $$divU_10,millicode
+       .import $$divU_12,millicode
+       .import $$divU_14,millicode
+       .import $$divU_15,millicode
+       .proc
+       .callinfo       millicode
+       .entry
+GSYM($$divU)
+/* The subtract is not nullified since it does no harm and can be used
+   by the two cases that branch back to "normal".  */
+       ldo     -1(arg1),temp           /* is there at most one bit set ? */
+       and,=   arg1,temp,r0            /* if so, denominator is power of 2 */
+       b       LREF(regular_seq)
+       addit,= 0,arg1,0                /* trap for zero dvr */
+       copy    arg0,retreg
+       extru,= arg1,15,16,temp         /* test denominator with 0xffff0000 */
+       extru   retreg,15,16,retreg     /* retreg = retreg >> 16 */
+       or      arg1,temp,arg1          /* arg1 = arg1 | (arg1 >> 16) */
+       ldi     0xcc,temp1              /* setup 0xcc in temp1 */
+       extru,= arg1,23,8,temp          /* test denominator with 0xff00 */
+       extru   retreg,23,24,retreg     /* retreg = retreg >> 8 */
+       or      arg1,temp,arg1          /* arg1 = arg1 | (arg1 >> 8) */
+       ldi     0xaa,temp               /* setup 0xaa in temp */
+       extru,= arg1,27,4,r0            /* test denominator with 0xf0 */
+       extru   retreg,27,28,retreg     /* retreg = retreg >> 4 */
+       and,=   arg1,temp1,r0           /* test denominator with 0xcc */
+       extru   retreg,29,30,retreg     /* retreg = retreg >> 2 */
+       and,=   arg1,temp,r0            /* test denominator with 0xaa */
+       extru   retreg,30,31,retreg     /* retreg = retreg >> 1 */
+       MILLIRETN
+       nop     
+LSYM(regular_seq)
+       comib,>=  15,arg1,LREF(special_divisor)
+       subi    0,arg1,temp             /* clear carry, negate the divisor */
+       ds      r0,temp,r0              /* set V-bit to 1 */
+LSYM(normal)
+       add     arg0,arg0,retreg        /* shift msb bit into carry */
+       ds      r0,arg1,temp            /* 1st divide step, if no carry */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 2nd divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 3rd divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 4th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 5th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 6th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 7th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 8th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 9th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 10th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 11th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 12th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 13th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 14th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 15th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 16th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 17th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 18th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 19th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 20th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 21st divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 22nd divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 23rd divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 24th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 25th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 26th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 27th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 28th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 29th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 30th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 31st divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 32nd divide step, */
+       MILLIRET
+       addc    retreg,retreg,retreg    /* shift last retreg bit into retreg */
+
+/* Handle the cases where divisor is a small constant or has high bit on.  */
+LSYM(special_divisor)
+/*     blr     arg1,r0 */
+/*     comib,>,n  0,arg1,LREF(big_divisor) ; nullify previous instruction */
+
+/* Pratap 8/13/90. The 815 Stirling chip set has a bug that prevents us from
+   generating such a blr, comib sequence. A problem in nullification. So I
+   rewrote this code.  */
+
+#if defined(CONFIG_64BIT)
+/* Clear the upper 32 bits of the arg1 register.  We are working with
+   small divisors (and 32-bit unsigned integers)   We must not be mislead
+   by "1" bits left in the upper 32 bits.  */
+       depd %r0,31,32,%r25
+#endif
+       comib,> 0,arg1,LREF(big_divisor)
+       nop
+       blr     arg1,r0
+       nop
+
+LSYM(zero_divisor)     /* this label is here to provide external visibility */
+       addit,= 0,arg1,0                /* trap for zero dvr */
+       nop
+       MILLIRET                        /* divisor == 1 */
+       copy    arg0,retreg
+       MILLIRET                        /* divisor == 2 */
+       extru   arg0,30,31,retreg
+       MILLI_BEN($$divU_3)             /* divisor == 3 */
+       nop
+       MILLIRET                        /* divisor == 4 */
+       extru   arg0,29,30,retreg
+       MILLI_BEN($$divU_5)             /* divisor == 5 */
+       nop
+       MILLI_BEN($$divU_6)             /* divisor == 6 */
+       nop
+       MILLI_BEN($$divU_7)             /* divisor == 7 */
+       nop
+       MILLIRET                        /* divisor == 8 */
+       extru   arg0,28,29,retreg
+       MILLI_BEN($$divU_9)             /* divisor == 9 */
+       nop
+       MILLI_BEN($$divU_10)            /* divisor == 10 */
+       nop
+       b       LREF(normal)            /* divisor == 11 */
+       ds      r0,temp,r0              /* set V-bit to 1 */
+       MILLI_BEN($$divU_12)            /* divisor == 12 */
+       nop
+       b       LREF(normal)            /* divisor == 13 */
+       ds      r0,temp,r0              /* set V-bit to 1 */
+       MILLI_BEN($$divU_14)            /* divisor == 14 */
+       nop
+       MILLI_BEN($$divU_15)            /* divisor == 15 */
+       nop
+
+/* Handle the case where the high bit is on in the divisor.
+   Compute:    if( dividend>=divisor) quotient=1; else quotient=0;
+   Note:       dividend>==divisor iff dividend-divisor does not borrow
+   and         not borrow iff carry.  */
+LSYM(big_divisor)
+       sub     arg0,arg1,r0
+       MILLIRET
+       addc    r0,r0,retreg
+       .exit
+       .procend
+       .end
+#endif
diff --git a/arch/parisc/lib/milli/div_const.S b/arch/parisc/lib/milli/div_const.S
new file mode 100644 (file)
index 0000000..dd66007
--- /dev/null
@@ -0,0 +1,682 @@
+/* 32 and 64-bit millicode, original author Hewlett-Packard
+   adapted for gcc by Paul Bame <bame@debian.org>
+   and Alan Modra <alan@linuxcare.com.au>.
+
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This file is part of GCC and is released under the terms of
+   of the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+   See the file COPYING in the top-level GCC source directory for a copy
+   of the license.  */
+
+#include "milli.h"
+
+#ifdef L_div_const
+/* ROUTINE:    $$divI_2
+   .           $$divI_3        $$divU_3
+   .           $$divI_4
+   .           $$divI_5        $$divU_5
+   .           $$divI_6        $$divU_6
+   .           $$divI_7        $$divU_7
+   .           $$divI_8
+   .           $$divI_9        $$divU_9
+   .           $$divI_10       $$divU_10
+   .
+   .           $$divI_12       $$divU_12
+   .
+   .           $$divI_14       $$divU_14
+   .           $$divI_15       $$divU_15
+   .           $$divI_16
+   .           $$divI_17       $$divU_17
+   .
+   .   Divide by selected constants for single precision binary integers.
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 =  undefined
+   .   arg1 =  undefined
+   .   ret1 =  quotient
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   =  undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions: NONE
+   .   Changes memory at the following places:  NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable.
+   .   Does not create a stack frame.
+   .   Suitable for internal or external millicode.
+   .   Assumes the special millicode register conventions.
+
+   DISCUSSION:
+   .   Calls other millicode routines using mrp:  NONE
+   .   Calls other millicode routines:  NONE  */
+
+
+/* TRUNCATED DIVISION BY SMALL INTEGERS
+
+   We are interested in q(x) = floor(x/y), where x >= 0 and y > 0
+   (with y fixed).
+
+   Let a = floor(z/y), for some choice of z.  Note that z will be
+   chosen so that division by z is cheap.
+
+   Let r be the remainder(z/y).  In other words, r = z - ay.
+
+   Now, our method is to choose a value for b such that
+
+   q'(x) = floor((ax+b)/z)
+
+   is equal to q(x) over as large a range of x as possible.  If the
+   two are equal over a sufficiently large range, and if it is easy to
+   form the product (ax), and it is easy to divide by z, then we can
+   perform the division much faster than the general division algorithm.
+
+   So, we want the following to be true:
+
+   .   For x in the following range:
+   .
+   .       ky <= x < (k+1)y
+   .
+   .   implies that
+   .
+   .       k <= (ax+b)/z < (k+1)
+
+   We want to determine b such that this is true for all k in the
+   range {0..K} for some maximum K.
+
+   Since (ax+b) is an increasing function of x, we can take each
+   bound separately to determine the "best" value for b.
+
+   (ax+b)/z < (k+1)           implies
+
+   (a((k+1)y-1)+b < (k+1)z     implies
+
+   b < a + (k+1)(z-ay)        implies
+
+   b < a + (k+1)r
+
+   This needs to be true for all k in the range {0..K}.  In
+   particular, it is true for k = 0 and this leads to a maximum
+   acceptable value for b.
+
+   b < a+r   or   b <= a+r-1
+
+   Taking the other bound, we have
+
+   k <= (ax+b)/z              implies
+
+   k <= (aky+b)/z             implies
+
+   k(z-ay) <= b                       implies
+
+   kr <= b
+
+   Clearly, the largest range for k will be achieved by maximizing b,
+   when r is not zero. When r is zero, then the simplest choice for b
+   is 0.  When r is not 0, set
+
+   .   b = a+r-1
+
+   Now, by construction, q'(x) = floor((ax+b)/z) = q(x) = floor(x/y)
+   for all x in the range:
+
+   .   0 <= x < (K+1)y
+
+   We need to determine what K is.  Of our two bounds,
+
+   .   b < a+(k+1)r    is satisfied for all k >= 0, by construction.
+
+   The other bound is
+
+   .   kr <= b
+
+   This is always true if r = 0.  If r is not 0 (the usual case), then
+   K = floor((a+r-1)/r), is the maximum value for k.
+
+   Therefore, the formula q'(x) = floor((ax+b)/z) yields the correct
+   answer for q(x) = floor(x/y) when x is in the range
+
+   (0,(K+1)y-1)               K = floor((a+r-1)/r)
+
+   To be most useful, we want (K+1)y-1 = (max x) >= 2**32-1 so that
+   the formula for q'(x) yields the correct value of q(x) for all x
+   representable by a single word in HPPA.
+
+   We are also constrained in that computing the product (ax), adding
+   b, and dividing by z must all be done quickly, otherwise we will be
+   better off going through the general algorithm using the DS
+   instruction, which uses approximately 70 cycles.
+
+   For each y, there is a choice of z which satisfies the constraints
+   for (K+1)y >= 2**32.  We may not, however, be able to satisfy the
+   timing constraints for arbitrary y. It seems that z being equal to
+   a power of 2 or a power of 2 minus 1 is as good as we can do, since
+   it minimizes the time to do division by z.  We want the choice of z
+   to also result in a value for (a) that minimizes the computation of
+   the product (ax).  This is best achieved if (a) has a regular bit
+   pattern (so the multiplication can be done with shifts and adds).
+   The value of (a) also needs to be less than 2**32 so the product is
+   always guaranteed to fit in 2 words.
+
+   In actual practice, the following should be done:
+
+   1) For negative x, you should take the absolute value and remember
+   .  the fact so that the result can be negated.  This obviously does
+   .  not apply in the unsigned case.
+   2) For even y, you should factor out the power of 2 that divides y
+   .  and divide x by it.  You can then proceed by dividing by the
+   .  odd factor of y.
+
+   Here is a table of some odd values of y, and corresponding choices
+   for z which are "good".
+
+    y    z       r      a (hex)     max x (hex)
+
+    3  2**32     1     55555555      100000001
+    5  2**32     1     33333333      100000003
+    7  2**24-1   0       249249     (infinite)
+    9  2**24-1   0       1c71c7     (infinite)
+   11  2**20-1   0        1745d     (infinite)
+   13  2**24-1   0       13b13b     (infinite)
+   15  2**32     1     11111111      10000000d
+   17  2**32     1      f0f0f0f      10000000f
+
+   If r is 1, then b = a+r-1 = a.  This simplifies the computation
+   of (ax+b), since you can compute (x+1)(a) instead.  If r is 0,
+   then b = 0 is ok to use which simplifies (ax+b).
+
+   The bit patterns for 55555555, 33333333, and 11111111 are obviously
+   very regular.  The bit patterns for the other values of a above are:
+
+    y     (hex)          (binary)
+
+    7    249249  001001001001001001001001  << regular >>
+    9    1c71c7  000111000111000111000111  << regular >>
+   11     1745d  000000010111010001011101  << irregular >>
+   13    13b13b  000100111011000100111011  << irregular >>
+
+   The bit patterns for (a) corresponding to (y) of 11 and 13 may be
+   too irregular to warrant using this method.
+
+   When z is a power of 2 minus 1, then the division by z is slightly
+   more complicated, involving an iterative solution.
+
+   The code presented here solves division by 1 through 17, except for
+   11 and 13. There are algorithms for both signed and unsigned
+   quantities given.
+
+   TIMINGS (cycles)
+
+   divisor  positive  negative unsigned
+
+   .   1       2          2         2
+   .   2       4          4         2
+   .   3       19        21        19
+   .   4       4          4         2
+   .   5       18        22        19
+   .   6       19        22        19
+   .   8       4          4         2
+   .  10       18        19        17
+   .  12       18        20        18
+   .  15       16        18        16
+   .  16       4          4         2
+   .  17       16        18        16
+
+   Now, the algorithm for 7, 9, and 14 is an iterative one.  That is,
+   a loop body is executed until the tentative quotient is 0.  The
+   number of times the loop body is executed varies depending on the
+   dividend, but is never more than two times. If the dividend is
+   less than the divisor, then the loop body is not executed at all.
+   Each iteration adds 4 cycles to the timings.
+
+   divisor  positive  negative unsigned
+
+   .   7       19+4n    20+4n     20+4n    n = number of iterations
+   .   9       21+4n    22+4n     21+4n
+   .  14       21+4n    22+4n     20+4n
+
+   To give an idea of how the number of iterations varies, here is a
+   table of dividend versus number of iterations when dividing by 7.
+
+   smallest     largest       required
+   dividend    dividend      iterations
+
+   .   0            6              0
+   .   7        0x6ffffff          1
+   0x1000006   0xffffffff          2
+
+   There is some overlap in the range of numbers requiring 1 and 2
+   iterations. */
+
+RDEFINE(t2,r1)
+RDEFINE(x2,arg0)       /*  r26 */
+RDEFINE(t1,arg1)       /*  r25 */
+RDEFINE(x1,ret1)       /*  r29 */
+
+       SUBSPA_MILLI_DIV
+       ATTR_MILLI
+
+       .proc
+       .callinfo       millicode
+       .entry
+/* NONE of these routines require a stack frame
+   ALL of these routines are unwindable from millicode */
+
+GSYM($$divide_by_constant)
+       .export $$divide_by_constant,millicode
+/*  Provides a "nice" label for the code covered by the unwind descriptor
+    for things like gprof.  */
+
+/* DIVISION BY 2 (shift by 1) */
+GSYM($$divI_2)
+       .export         $$divI_2,millicode
+       comclr,>=       arg0,0,0
+       addi            1,arg0,arg0
+       MILLIRET
+       extrs           arg0,30,31,ret1
+
+
+/* DIVISION BY 4 (shift by 2) */
+GSYM($$divI_4)
+       .export         $$divI_4,millicode
+       comclr,>=       arg0,0,0
+       addi            3,arg0,arg0
+       MILLIRET
+       extrs           arg0,29,30,ret1
+
+
+/* DIVISION BY 8 (shift by 3) */
+GSYM($$divI_8)
+       .export         $$divI_8,millicode
+       comclr,>=       arg0,0,0
+       addi            7,arg0,arg0
+       MILLIRET
+       extrs           arg0,28,29,ret1
+
+/* DIVISION BY 16 (shift by 4) */
+GSYM($$divI_16)
+       .export         $$divI_16,millicode
+       comclr,>=       arg0,0,0
+       addi            15,arg0,arg0
+       MILLIRET
+       extrs           arg0,27,28,ret1
+
+/****************************************************************************
+*
+*      DIVISION BY DIVISORS OF FFFFFFFF, and powers of 2 times these
+*
+*      includes 3,5,15,17 and also 6,10,12
+*
+****************************************************************************/
+
+/* DIVISION BY 3 (use z = 2**32; a = 55555555) */
+
+GSYM($$divI_3)
+       .export         $$divI_3,millicode
+       comb,<,N        x2,0,LREF(neg3)
+
+       addi            1,x2,x2         /* this cannot overflow */
+       extru           x2,1,2,x1       /* multiply by 5 to get started */
+       sh2add          x2,x2,x2
+       b               LREF(pos)
+       addc            x1,0,x1
+
+LSYM(neg3)
+       subi            1,x2,x2         /* this cannot overflow */
+       extru           x2,1,2,x1       /* multiply by 5 to get started */
+       sh2add          x2,x2,x2
+       b               LREF(neg)
+       addc            x1,0,x1
+
+GSYM($$divU_3)
+       .export         $$divU_3,millicode
+       addi            1,x2,x2         /* this CAN overflow */
+       addc            0,0,x1
+       shd             x1,x2,30,t1     /* multiply by 5 to get started */
+       sh2add          x2,x2,x2
+       b               LREF(pos)
+       addc            x1,t1,x1
+
+/* DIVISION BY 5 (use z = 2**32; a = 33333333) */
+
+GSYM($$divI_5)
+       .export         $$divI_5,millicode
+       comb,<,N        x2,0,LREF(neg5)
+
+       addi            3,x2,t1         /* this cannot overflow */
+       sh1add          x2,t1,x2        /* multiply by 3 to get started */
+       b               LREF(pos)
+       addc            0,0,x1
+
+LSYM(neg5)
+       sub             0,x2,x2         /* negate x2                    */
+       addi            1,x2,x2         /* this cannot overflow */
+       shd             0,x2,31,x1      /* get top bit (can be 1)       */
+       sh1add          x2,x2,x2        /* multiply by 3 to get started */
+       b               LREF(neg)
+       addc            x1,0,x1
+
+GSYM($$divU_5)
+       .export         $$divU_5,millicode
+       addi            1,x2,x2         /* this CAN overflow */
+       addc            0,0,x1
+       shd             x1,x2,31,t1     /* multiply by 3 to get started */
+       sh1add          x2,x2,x2
+       b               LREF(pos)
+       addc            t1,x1,x1
+
+/* DIVISION BY 6 (shift to divide by 2 then divide by 3) */
+GSYM($$divI_6)
+       .export         $$divI_6,millicode
+       comb,<,N        x2,0,LREF(neg6)
+       extru           x2,30,31,x2     /* divide by 2                  */
+       addi            5,x2,t1         /* compute 5*(x2+1) = 5*x2+5    */
+       sh2add          x2,t1,x2        /* multiply by 5 to get started */
+       b               LREF(pos)
+       addc            0,0,x1
+
+LSYM(neg6)
+       subi            2,x2,x2         /* negate, divide by 2, and add 1 */
+                                       /* negation and adding 1 are done */
+                                       /* at the same time by the SUBI   */
+       extru           x2,30,31,x2
+       shd             0,x2,30,x1
+       sh2add          x2,x2,x2        /* multiply by 5 to get started */
+       b               LREF(neg)
+       addc            x1,0,x1
+
+GSYM($$divU_6)
+       .export         $$divU_6,millicode
+       extru           x2,30,31,x2     /* divide by 2 */
+       addi            1,x2,x2         /* cannot carry */
+       shd             0,x2,30,x1      /* multiply by 5 to get started */
+       sh2add          x2,x2,x2
+       b               LREF(pos)
+       addc            x1,0,x1
+
+/* DIVISION BY 10 (shift to divide by 2 then divide by 5) */
+GSYM($$divU_10)
+       .export         $$divU_10,millicode
+       extru           x2,30,31,x2     /* divide by 2 */
+       addi            3,x2,t1         /* compute 3*(x2+1) = (3*x2)+3  */
+       sh1add          x2,t1,x2        /* multiply by 3 to get started */
+       addc            0,0,x1
+LSYM(pos)
+       shd             x1,x2,28,t1     /* multiply by 0x11 */
+       shd             x2,0,28,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+LSYM(pos_for_17)
+       shd             x1,x2,24,t1     /* multiply by 0x101 */
+       shd             x2,0,24,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+
+       shd             x1,x2,16,t1     /* multiply by 0x10001 */
+       shd             x2,0,16,t2
+       add             x2,t2,x2
+       MILLIRET
+       addc            x1,t1,x1
+
+GSYM($$divI_10)
+       .export         $$divI_10,millicode
+       comb,<          x2,0,LREF(neg10)
+       copy            0,x1
+       extru           x2,30,31,x2     /* divide by 2 */
+       addib,TR        1,x2,LREF(pos)  /* add 1 (cannot overflow)     */
+       sh1add          x2,x2,x2        /* multiply by 3 to get started */
+
+LSYM(neg10)
+       subi            2,x2,x2         /* negate, divide by 2, and add 1 */
+                                       /* negation and adding 1 are done */
+                                       /* at the same time by the SUBI   */
+       extru           x2,30,31,x2
+       sh1add          x2,x2,x2        /* multiply by 3 to get started */
+LSYM(neg)
+       shd             x1,x2,28,t1     /* multiply by 0x11 */
+       shd             x2,0,28,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+LSYM(neg_for_17)
+       shd             x1,x2,24,t1     /* multiply by 0x101 */
+       shd             x2,0,24,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+
+       shd             x1,x2,16,t1     /* multiply by 0x10001 */
+       shd             x2,0,16,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+       MILLIRET
+       sub             0,x1,x1
+
+/* DIVISION BY 12 (shift to divide by 4 then divide by 3) */
+GSYM($$divI_12)
+       .export         $$divI_12,millicode
+       comb,<          x2,0,LREF(neg12)
+       copy            0,x1
+       extru           x2,29,30,x2     /* divide by 4                  */
+       addib,tr        1,x2,LREF(pos)  /* compute 5*(x2+1) = 5*x2+5    */
+       sh2add          x2,x2,x2        /* multiply by 5 to get started */
+
+LSYM(neg12)
+       subi            4,x2,x2         /* negate, divide by 4, and add 1 */
+                                       /* negation and adding 1 are done */
+                                       /* at the same time by the SUBI   */
+       extru           x2,29,30,x2
+       b               LREF(neg)
+       sh2add          x2,x2,x2        /* multiply by 5 to get started */
+
+GSYM($$divU_12)
+       .export         $$divU_12,millicode
+       extru           x2,29,30,x2     /* divide by 4   */
+       addi            5,x2,t1         /* cannot carry */
+       sh2add          x2,t1,x2        /* multiply by 5 to get started */
+       b               LREF(pos)
+       addc            0,0,x1
+
+/* DIVISION BY 15 (use z = 2**32; a = 11111111) */
+GSYM($$divI_15)
+       .export         $$divI_15,millicode
+       comb,<          x2,0,LREF(neg15)
+       copy            0,x1
+       addib,tr        1,x2,LREF(pos)+4
+       shd             x1,x2,28,t1
+
+LSYM(neg15)
+       b               LREF(neg)
+       subi            1,x2,x2
+
+GSYM($$divU_15)
+       .export         $$divU_15,millicode
+       addi            1,x2,x2         /* this CAN overflow */
+       b               LREF(pos)
+       addc            0,0,x1
+
+/* DIVISION BY 17 (use z = 2**32; a =  f0f0f0f) */
+GSYM($$divI_17)
+       .export         $$divI_17,millicode
+       comb,<,n        x2,0,LREF(neg17)
+       addi            1,x2,x2         /* this cannot overflow */
+       shd             0,x2,28,t1      /* multiply by 0xf to get started */
+       shd             x2,0,28,t2
+       sub             t2,x2,x2
+       b               LREF(pos_for_17)
+       subb            t1,0,x1
+
+LSYM(neg17)
+       subi            1,x2,x2         /* this cannot overflow */
+       shd             0,x2,28,t1      /* multiply by 0xf to get started */
+       shd             x2,0,28,t2
+       sub             t2,x2,x2
+       b               LREF(neg_for_17)
+       subb            t1,0,x1
+
+GSYM($$divU_17)
+       .export         $$divU_17,millicode
+       addi            1,x2,x2         /* this CAN overflow */
+       addc            0,0,x1
+       shd             x1,x2,28,t1     /* multiply by 0xf to get started */
+LSYM(u17)
+       shd             x2,0,28,t2
+       sub             t2,x2,x2
+       b               LREF(pos_for_17)
+       subb            t1,x1,x1
+
+
+/* DIVISION BY DIVISORS OF FFFFFF, and powers of 2 times these
+   includes 7,9 and also 14
+
+
+   z = 2**24-1
+   r = z mod x = 0
+
+   so choose b = 0
+
+   Also, in order to divide by z = 2**24-1, we approximate by dividing
+   by (z+1) = 2**24 (which is easy), and then correcting.
+
+   (ax) = (z+1)q' + r
+   .   = zq' + (q'+r)
+
+   So to compute (ax)/z, compute q' = (ax)/(z+1) and r = (ax) mod (z+1)
+   Then the true remainder of (ax)/z is (q'+r).  Repeat the process
+   with this new remainder, adding the tentative quotients together,
+   until a tentative quotient is 0 (and then we are done).  There is
+   one last correction to be done.  It is possible that (q'+r) = z.
+   If so, then (q'+r)/(z+1) = 0 and it looks like we are done. But,
+   in fact, we need to add 1 more to the quotient.  Now, it turns
+   out that this happens if and only if the original value x is
+   an exact multiple of y.  So, to avoid a three instruction test at
+   the end, instead use 1 instruction to add 1 to x at the beginning.  */
+
+/* DIVISION BY 7 (use z = 2**24-1; a = 249249) */
+GSYM($$divI_7)
+       .export         $$divI_7,millicode
+       comb,<,n        x2,0,LREF(neg7)
+LSYM(7)
+       addi            1,x2,x2         /* cannot overflow */
+       shd             0,x2,29,x1
+       sh3add          x2,x2,x2
+       addc            x1,0,x1
+LSYM(pos7)
+       shd             x1,x2,26,t1
+       shd             x2,0,26,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+
+       shd             x1,x2,20,t1
+       shd             x2,0,20,t2
+       add             x2,t2,x2
+       addc            x1,t1,t1
+
+       /* computed <t1,x2>.  Now divide it by (2**24 - 1)      */
+
+       copy            0,x1
+       shd,=           t1,x2,24,t1     /* tentative quotient  */
+LSYM(1)
+       addb,tr         t1,x1,LREF(2)   /* add to previous quotient   */
+       extru           x2,31,24,x2     /* new remainder (unadjusted) */
+
+       MILLIRETN
+
+LSYM(2)
+       addb,tr         t1,x2,LREF(1)   /* adjust remainder */
+       extru,=         x2,7,8,t1       /* new quotient     */
+
+LSYM(neg7)
+       subi            1,x2,x2         /* negate x2 and add 1 */
+LSYM(8)
+       shd             0,x2,29,x1
+       sh3add          x2,x2,x2
+       addc            x1,0,x1
+
+LSYM(neg7_shift)
+       shd             x1,x2,26,t1
+       shd             x2,0,26,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+
+       shd             x1,x2,20,t1
+       shd             x2,0,20,t2
+       add             x2,t2,x2
+       addc            x1,t1,t1
+
+       /* computed <t1,x2>.  Now divide it by (2**24 - 1)      */
+
+       copy            0,x1
+       shd,=           t1,x2,24,t1     /* tentative quotient  */
+LSYM(3)
+       addb,tr         t1,x1,LREF(4)   /* add to previous quotient   */
+       extru           x2,31,24,x2     /* new remainder (unadjusted) */
+
+       MILLIRET
+       sub             0,x1,x1         /* negate result    */
+
+LSYM(4)
+       addb,tr         t1,x2,LREF(3)   /* adjust remainder */
+       extru,=         x2,7,8,t1       /* new quotient     */
+
+GSYM($$divU_7)
+       .export         $$divU_7,millicode
+       addi            1,x2,x2         /* can carry */
+       addc            0,0,x1
+       shd             x1,x2,29,t1
+       sh3add          x2,x2,x2
+       b               LREF(pos7)
+       addc            t1,x1,x1
+
+/* DIVISION BY 9 (use z = 2**24-1; a = 1c71c7) */
+GSYM($$divI_9)
+       .export         $$divI_9,millicode
+       comb,<,n        x2,0,LREF(neg9)
+       addi            1,x2,x2         /* cannot overflow */
+       shd             0,x2,29,t1
+       shd             x2,0,29,t2
+       sub             t2,x2,x2
+       b               LREF(pos7)
+       subb            t1,0,x1
+
+LSYM(neg9)
+       subi            1,x2,x2         /* negate and add 1 */
+       shd             0,x2,29,t1
+       shd             x2,0,29,t2
+       sub             t2,x2,x2
+       b               LREF(neg7_shift)
+       subb            t1,0,x1
+
+GSYM($$divU_9)
+       .export         $$divU_9,millicode
+       addi            1,x2,x2         /* can carry */
+       addc            0,0,x1
+       shd             x1,x2,29,t1
+       shd             x2,0,29,t2
+       sub             t2,x2,x2
+       b               LREF(pos7)
+       subb            t1,x1,x1
+
+/* DIVISION BY 14 (shift to divide by 2 then divide by 7) */
+GSYM($$divI_14)
+       .export         $$divI_14,millicode
+       comb,<,n        x2,0,LREF(neg14)
+GSYM($$divU_14)
+       .export         $$divU_14,millicode
+       b               LREF(7)         /* go to 7 case */
+       extru           x2,30,31,x2     /* divide by 2  */
+
+LSYM(neg14)
+       subi            2,x2,x2         /* negate (and add 2) */
+       b               LREF(8)
+       extru           x2,30,31,x2     /* divide by 2        */
+       .exit
+       .procend
+       .end
+#endif
diff --git a/arch/parisc/lib/milli/dyncall.S b/arch/parisc/lib/milli/dyncall.S
new file mode 100644 (file)
index 0000000..27f9ca5
--- /dev/null
@@ -0,0 +1,32 @@
+/* 32 and 64-bit millicode, original author Hewlett-Packard
+   adapted for gcc by Paul Bame <bame@debian.org>
+   and Alan Modra <alan@linuxcare.com.au>.
+
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This file is part of GCC and is released under the terms of
+   of the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+   See the file COPYING in the top-level GCC source directory for a copy
+   of the license.  */
+
+#include "milli.h"
+
+#ifdef L_dyncall
+       SUBSPA_MILLI
+       ATTR_DATA
+GSYM($$dyncall)
+       .export $$dyncall,millicode
+       .proc
+       .callinfo       millicode
+       .entry
+       bb,>=,n %r22,30,LREF(1)         ; branch if not plabel address
+       depi    0,31,2,%r22             ; clear the two least significant bits
+       ldw     4(%r22),%r19            ; load new LTP value
+       ldw     0(%r22),%r22            ; load address of target
+LSYM(1)
+       bv      %r0(%r22)               ; branch to the real target
+       stw     %r2,-24(%r30)           ; save return address into frame marker
+       .exit
+       .procend
+#endif
diff --git a/arch/parisc/lib/milli/milli.S b/arch/parisc/lib/milli/milli.S
new file mode 100644 (file)
index 0000000..47c6cde
--- /dev/null
@@ -0,0 +1,2071 @@
+/* 32 and 64-bit millicode, original author Hewlett-Packard
+   adapted for gcc by Paul Bame <bame@debian.org>
+   and Alan Modra <alan@linuxcare.com.au>.
+
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This file is part of GCC and is released under the terms of
+   of the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+   See the file COPYING in the top-level GCC source directory for a copy
+   of the license.  */
+
+#ifdef CONFIG_64BIT
+        .level  2.0w
+#endif
+
+/* Hardware General Registers.  */
+r0:    .reg    %r0
+r1:    .reg    %r1
+r2:    .reg    %r2
+r3:    .reg    %r3
+r4:    .reg    %r4
+r5:    .reg    %r5
+r6:    .reg    %r6
+r7:    .reg    %r7
+r8:    .reg    %r8
+r9:    .reg    %r9
+r10:   .reg    %r10
+r11:   .reg    %r11
+r12:   .reg    %r12
+r13:   .reg    %r13
+r14:   .reg    %r14
+r15:   .reg    %r15
+r16:   .reg    %r16
+r17:   .reg    %r17
+r18:   .reg    %r18
+r19:   .reg    %r19
+r20:   .reg    %r20
+r21:   .reg    %r21
+r22:   .reg    %r22
+r23:   .reg    %r23
+r24:   .reg    %r24
+r25:   .reg    %r25
+r26:   .reg    %r26
+r27:   .reg    %r27
+r28:   .reg    %r28
+r29:   .reg    %r29
+r30:   .reg    %r30
+r31:   .reg    %r31
+
+/* Hardware Space Registers.  */
+sr0:   .reg    %sr0
+sr1:   .reg    %sr1
+sr2:   .reg    %sr2
+sr3:   .reg    %sr3
+sr4:   .reg    %sr4
+sr5:   .reg    %sr5
+sr6:   .reg    %sr6
+sr7:   .reg    %sr7
+
+/* Hardware Floating Point Registers.  */
+fr0:   .reg    %fr0
+fr1:   .reg    %fr1
+fr2:   .reg    %fr2
+fr3:   .reg    %fr3
+fr4:   .reg    %fr4
+fr5:   .reg    %fr5
+fr6:   .reg    %fr6
+fr7:   .reg    %fr7
+fr8:   .reg    %fr8
+fr9:   .reg    %fr9
+fr10:  .reg    %fr10
+fr11:  .reg    %fr11
+fr12:  .reg    %fr12
+fr13:  .reg    %fr13
+fr14:  .reg    %fr14
+fr15:  .reg    %fr15
+
+/* Hardware Control Registers.  */
+cr11:  .reg    %cr11
+sar:   .reg    %cr11   /* Shift Amount Register */
+
+/* Software Architecture General Registers.  */
+rp:    .reg    r2      /* return pointer */
+#ifdef CONFIG_64BIT
+mrp:   .reg    r2      /* millicode return pointer */
+#else
+mrp:   .reg    r31     /* millicode return pointer */
+#endif
+ret0:  .reg    r28     /* return value */
+ret1:  .reg    r29     /* return value (high part of double) */
+sp:    .reg    r30     /* stack pointer */
+dp:    .reg    r27     /* data pointer */
+arg0:  .reg    r26     /* argument */
+arg1:  .reg    r25     /* argument or high part of double argument */
+arg2:  .reg    r24     /* argument */
+arg3:  .reg    r23     /* argument or high part of double argument */
+
+/* Software Architecture Space Registers.  */
+/*             sr0     ; return link from BLE */
+sret:  .reg    sr1     /* return value */
+sarg:  .reg    sr1     /* argument */
+/*             sr4     ; PC SPACE tracker */
+/*             sr5     ; process private data */
+
+/* Frame Offsets (millicode convention!)  Used when calling other
+   millicode routines.  Stack unwinding is dependent upon these
+   definitions.  */
+r31_slot:      .equ    -20     /* "current RP" slot */
+sr0_slot:      .equ    -16     /* "static link" slot */
+#if defined(CONFIG_64BIT)
+mrp_slot:       .equ    -16    /* "current RP" slot */
+psp_slot:       .equ    -8     /* "previous SP" slot */
+#else
+mrp_slot:      .equ    -20     /* "current RP" slot (replacing "r31_slot") */
+#endif
+
+
+#define DEFINE(name,value)name:        .EQU    value
+#define RDEFINE(name,value)name:       .REG    value
+#ifdef milliext
+#define MILLI_BE(lbl)   BE    lbl(sr7,r0)
+#define MILLI_BEN(lbl)  BE,n  lbl(sr7,r0)
+#define MILLI_BLE(lbl) BLE   lbl(sr7,r0)
+#define MILLI_BLEN(lbl)        BLE,n lbl(sr7,r0)
+#define MILLIRETN      BE,n  0(sr0,mrp)
+#define MILLIRET       BE    0(sr0,mrp)
+#define MILLI_RETN     BE,n  0(sr0,mrp)
+#define MILLI_RET      BE    0(sr0,mrp)
+#else
+#define MILLI_BE(lbl)  B     lbl
+#define MILLI_BEN(lbl)  B,n   lbl
+#define MILLI_BLE(lbl) BL    lbl,mrp
+#define MILLI_BLEN(lbl)        BL,n  lbl,mrp
+#define MILLIRETN      BV,n  0(mrp)
+#define MILLIRET       BV    0(mrp)
+#define MILLI_RETN     BV,n  0(mrp)
+#define MILLI_RET      BV    0(mrp)
+#endif
+
+#define CAT(a,b)       a##b
+
+#define SUBSPA_MILLI    .section .text
+#define SUBSPA_MILLI_DIV .section .text.div,"ax",@progbits! .align 16
+#define SUBSPA_MILLI_MUL .section .text.mul,"ax",@progbits! .align 16
+#define ATTR_MILLI
+#define SUBSPA_DATA     .section .data
+#define ATTR_DATA
+#define GLOBAL          $global$
+#define GSYM(sym)       !sym:
+#define LSYM(sym)       !CAT(.L,sym:)
+#define LREF(sym)       CAT(.L,sym)
+
+#ifdef L_dyncall
+       SUBSPA_MILLI
+       ATTR_DATA
+GSYM($$dyncall)
+       .export $$dyncall,millicode
+       .proc
+       .callinfo       millicode
+       .entry
+       bb,>=,n %r22,30,LREF(1)         ; branch if not plabel address
+       depi    0,31,2,%r22             ; clear the two least significant bits
+       ldw     4(%r22),%r19            ; load new LTP value
+       ldw     0(%r22),%r22            ; load address of target
+LSYM(1)
+       bv      %r0(%r22)               ; branch to the real target
+       stw     %r2,-24(%r30)           ; save return address into frame marker
+       .exit
+       .procend
+#endif
+
+#ifdef L_divI
+/* ROUTINES:   $$divI, $$divoI
+
+   Single precision divide for signed binary integers.
+
+   The quotient is truncated towards zero.
+   The sign of the quotient is the XOR of the signs of the dividend and
+   divisor.
+   Divide by zero is trapped.
+   Divide of -2**31 by -1 is trapped for $$divoI but not for $$divI.
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   arg1 == divisor
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 =  undefined
+   .   arg1 =  undefined
+   .   ret1 =  quotient
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   =  undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions:
+   .           divisor is zero  (traps with ADDIT,=  0,25,0)
+   .           dividend==-2**31  and divisor==-1 and routine is $$divoI
+   .                            (traps with ADDO  26,25,0)
+   .   Changes memory at the following places:
+   .           NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable.
+   .   Suitable for internal or external millicode.
+   .   Assumes the special millicode register conventions.
+
+   DISCUSSION:
+   .   Branchs to other millicode routines using BE
+   .           $$div_# for # being 2,3,4,5,6,7,8,9,10,12,14,15
+   .
+   .   For selected divisors, calls a divide by constant routine written by
+   .   Karl Pettis.  Eligible divisors are 1..15 excluding 11 and 13.
+   .
+   .   The only overflow case is -2**31 divided by -1.
+   .   Both routines return -2**31 but only $$divoI traps.  */
+
+RDEFINE(temp,r1)
+RDEFINE(retreg,ret1)   /*  r29 */
+RDEFINE(temp1,arg0)
+       SUBSPA_MILLI_DIV
+       ATTR_MILLI
+       .import $$divI_2,millicode
+       .import $$divI_3,millicode
+       .import $$divI_4,millicode
+       .import $$divI_5,millicode
+       .import $$divI_6,millicode
+       .import $$divI_7,millicode
+       .import $$divI_8,millicode
+       .import $$divI_9,millicode
+       .import $$divI_10,millicode
+       .import $$divI_12,millicode
+       .import $$divI_14,millicode
+       .import $$divI_15,millicode
+       .export $$divI,millicode
+       .export $$divoI,millicode
+       .proc
+       .callinfo       millicode
+       .entry
+GSYM($$divoI)
+       comib,=,n  -1,arg1,LREF(negative1)      /*  when divisor == -1 */
+GSYM($$divI)
+       ldo     -1(arg1),temp           /*  is there at most one bit set ? */
+       and,<>  arg1,temp,r0            /*  if not, don't use power of 2 divide */
+       addi,>  0,arg1,r0               /*  if divisor > 0, use power of 2 divide */
+       b,n     LREF(neg_denom)
+LSYM(pow2)
+       addi,>= 0,arg0,retreg           /*  if numerator is negative, add the */
+       add     arg0,temp,retreg        /*  (denominaotr -1) to correct for shifts */
+       extru,= arg1,15,16,temp         /*  test denominator with 0xffff0000 */
+       extrs   retreg,15,16,retreg     /*  retreg = retreg >> 16 */
+       or      arg1,temp,arg1          /*  arg1 = arg1 | (arg1 >> 16) */
+       ldi     0xcc,temp1              /*  setup 0xcc in temp1 */
+       extru,= arg1,23,8,temp          /*  test denominator with 0xff00 */
+       extrs   retreg,23,24,retreg     /*  retreg = retreg >> 8 */
+       or      arg1,temp,arg1          /*  arg1 = arg1 | (arg1 >> 8) */
+       ldi     0xaa,temp               /*  setup 0xaa in temp */
+       extru,= arg1,27,4,r0            /*  test denominator with 0xf0 */
+       extrs   retreg,27,28,retreg     /*  retreg = retreg >> 4 */
+       and,=   arg1,temp1,r0           /*  test denominator with 0xcc */
+       extrs   retreg,29,30,retreg     /*  retreg = retreg >> 2 */
+       and,=   arg1,temp,r0            /*  test denominator with 0xaa */
+       extrs   retreg,30,31,retreg     /*  retreg = retreg >> 1 */
+       MILLIRETN
+LSYM(neg_denom)
+       addi,<  0,arg1,r0               /*  if arg1 >= 0, it's not power of 2 */
+       b,n     LREF(regular_seq)
+       sub     r0,arg1,temp            /*  make denominator positive */
+       comb,=,n  arg1,temp,LREF(regular_seq)   /*  test against 0x80000000 and 0 */
+       ldo     -1(temp),retreg         /*  is there at most one bit set ? */
+       and,=   temp,retreg,r0          /*  if so, the denominator is power of 2 */
+       b,n     LREF(regular_seq)
+       sub     r0,arg0,retreg          /*  negate numerator */
+       comb,=,n arg0,retreg,LREF(regular_seq) /*  test against 0x80000000 */
+       copy    retreg,arg0             /*  set up arg0, arg1 and temp  */
+       copy    temp,arg1               /*  before branching to pow2 */
+       b       LREF(pow2)
+       ldo     -1(arg1),temp
+LSYM(regular_seq)
+       comib,>>=,n 15,arg1,LREF(small_divisor)
+       add,>=  0,arg0,retreg           /*  move dividend, if retreg < 0, */
+LSYM(normal)
+       subi    0,retreg,retreg         /*    make it positive */
+       sub     0,arg1,temp             /*  clear carry,  */
+                                       /*    negate the divisor */
+       ds      0,temp,0                /*  set V-bit to the comple- */
+                                       /*    ment of the divisor sign */
+       add     retreg,retreg,retreg    /*  shift msb bit into carry */
+       ds      r0,arg1,temp            /*  1st divide step, if no carry */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  2nd divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  3rd divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  4th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  5th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  6th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  7th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  8th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  9th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  10th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  11th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  12th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  13th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  14th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  15th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  16th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  17th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  18th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  19th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  20th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  21st divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  22nd divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  23rd divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  24th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  25th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  26th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  27th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  28th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  29th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  30th divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  31st divide step */
+       addc    retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds      temp,arg1,temp          /*  32nd divide step, */
+       addc    retreg,retreg,retreg    /*  shift last retreg bit into retreg */
+       xor,>=  arg0,arg1,0             /*  get correct sign of quotient */
+         sub   0,retreg,retreg         /*    based on operand signs */
+       MILLIRETN
+       nop
+
+LSYM(small_divisor)
+
+#if defined(CONFIG_64BIT)
+/*  Clear the upper 32 bits of the arg1 register.  We are working with */
+/*  small divisors (and 32-bit integers)   We must not be mislead  */
+/*  by "1" bits left in the upper 32 bits.  */
+       depd %r0,31,32,%r25
+#endif
+       blr,n   arg1,r0
+       nop
+/*  table for divisor == 0,1, ... ,15 */
+       addit,= 0,arg1,r0       /*  trap if divisor == 0 */
+       nop
+       MILLIRET                /*  divisor == 1 */
+       copy    arg0,retreg
+       MILLI_BEN($$divI_2)     /*  divisor == 2 */
+       nop
+       MILLI_BEN($$divI_3)     /*  divisor == 3 */
+       nop
+       MILLI_BEN($$divI_4)     /*  divisor == 4 */
+       nop
+       MILLI_BEN($$divI_5)     /*  divisor == 5 */
+       nop
+       MILLI_BEN($$divI_6)     /*  divisor == 6 */
+       nop
+       MILLI_BEN($$divI_7)     /*  divisor == 7 */
+       nop
+       MILLI_BEN($$divI_8)     /*  divisor == 8 */
+       nop
+       MILLI_BEN($$divI_9)     /*  divisor == 9 */
+       nop
+       MILLI_BEN($$divI_10)    /*  divisor == 10 */
+       nop
+       b       LREF(normal)            /*  divisor == 11 */
+       add,>=  0,arg0,retreg
+       MILLI_BEN($$divI_12)    /*  divisor == 12 */
+       nop
+       b       LREF(normal)            /*  divisor == 13 */
+       add,>=  0,arg0,retreg
+       MILLI_BEN($$divI_14)    /*  divisor == 14 */
+       nop
+       MILLI_BEN($$divI_15)    /*  divisor == 15 */
+       nop
+
+LSYM(negative1)
+       sub     0,arg0,retreg   /*  result is negation of dividend */
+       MILLIRET
+       addo    arg0,arg1,r0    /*  trap iff dividend==0x80000000 && divisor==-1 */
+       .exit
+       .procend
+       .end
+#endif
+
+#ifdef L_divU
+/* ROUTINE:    $$divU
+   .
+   .   Single precision divide for unsigned integers.
+   .
+   .   Quotient is truncated towards zero.
+   .   Traps on divide by zero.
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   arg1 == divisor
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 =  undefined
+   .   arg1 =  undefined
+   .   ret1 =  quotient
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   =  undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions:
+   .           divisor is zero
+   .   Changes memory at the following places:
+   .           NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable.
+   .   Does not create a stack frame.
+   .   Suitable for internal or external millicode.
+   .   Assumes the special millicode register conventions.
+
+   DISCUSSION:
+   .   Branchs to other millicode routines using BE:
+   .           $$divU_# for 3,5,6,7,9,10,12,14,15
+   .
+   .   For selected small divisors calls the special divide by constant
+   .   routines written by Karl Pettis.  These are: 3,5,6,7,9,10,12,14,15.  */
+
+RDEFINE(temp,r1)
+RDEFINE(retreg,ret1)   /* r29 */
+RDEFINE(temp1,arg0)
+       SUBSPA_MILLI_DIV
+       ATTR_MILLI
+       .export $$divU,millicode
+       .import $$divU_3,millicode
+       .import $$divU_5,millicode
+       .import $$divU_6,millicode
+       .import $$divU_7,millicode
+       .import $$divU_9,millicode
+       .import $$divU_10,millicode
+       .import $$divU_12,millicode
+       .import $$divU_14,millicode
+       .import $$divU_15,millicode
+       .proc
+       .callinfo       millicode
+       .entry
+GSYM($$divU)
+/* The subtract is not nullified since it does no harm and can be used
+   by the two cases that branch back to "normal".  */
+       ldo     -1(arg1),temp           /* is there at most one bit set ? */
+       and,=   arg1,temp,r0            /* if so, denominator is power of 2 */
+       b       LREF(regular_seq)
+       addit,= 0,arg1,0                /* trap for zero dvr */
+       copy    arg0,retreg
+       extru,= arg1,15,16,temp         /* test denominator with 0xffff0000 */
+       extru   retreg,15,16,retreg     /* retreg = retreg >> 16 */
+       or      arg1,temp,arg1          /* arg1 = arg1 | (arg1 >> 16) */
+       ldi     0xcc,temp1              /* setup 0xcc in temp1 */
+       extru,= arg1,23,8,temp          /* test denominator with 0xff00 */
+       extru   retreg,23,24,retreg     /* retreg = retreg >> 8 */
+       or      arg1,temp,arg1          /* arg1 = arg1 | (arg1 >> 8) */
+       ldi     0xaa,temp               /* setup 0xaa in temp */
+       extru,= arg1,27,4,r0            /* test denominator with 0xf0 */
+       extru   retreg,27,28,retreg     /* retreg = retreg >> 4 */
+       and,=   arg1,temp1,r0           /* test denominator with 0xcc */
+       extru   retreg,29,30,retreg     /* retreg = retreg >> 2 */
+       and,=   arg1,temp,r0            /* test denominator with 0xaa */
+       extru   retreg,30,31,retreg     /* retreg = retreg >> 1 */
+       MILLIRETN
+       nop     
+LSYM(regular_seq)
+       comib,>=  15,arg1,LREF(special_divisor)
+       subi    0,arg1,temp             /* clear carry, negate the divisor */
+       ds      r0,temp,r0              /* set V-bit to 1 */
+LSYM(normal)
+       add     arg0,arg0,retreg        /* shift msb bit into carry */
+       ds      r0,arg1,temp            /* 1st divide step, if no carry */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 2nd divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 3rd divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 4th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 5th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 6th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 7th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 8th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 9th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 10th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 11th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 12th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 13th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 14th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 15th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 16th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 17th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 18th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 19th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 20th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 21st divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 22nd divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 23rd divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 24th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 25th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 26th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 27th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 28th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 29th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 30th divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 31st divide step */
+       addc    retreg,retreg,retreg    /* shift retreg with/into carry */
+       ds      temp,arg1,temp          /* 32nd divide step, */
+       MILLIRET
+       addc    retreg,retreg,retreg    /* shift last retreg bit into retreg */
+
+/* Handle the cases where divisor is a small constant or has high bit on.  */
+LSYM(special_divisor)
+/*     blr     arg1,r0 */
+/*     comib,>,n  0,arg1,LREF(big_divisor) ; nullify previous instruction */
+
+/* Pratap 8/13/90. The 815 Stirling chip set has a bug that prevents us from
+   generating such a blr, comib sequence. A problem in nullification. So I
+   rewrote this code.  */
+
+#if defined(CONFIG_64BIT)
+/* Clear the upper 32 bits of the arg1 register.  We are working with
+   small divisors (and 32-bit unsigned integers)   We must not be mislead
+   by "1" bits left in the upper 32 bits.  */
+       depd %r0,31,32,%r25
+#endif
+       comib,> 0,arg1,LREF(big_divisor)
+       nop
+       blr     arg1,r0
+       nop
+
+LSYM(zero_divisor)     /* this label is here to provide external visibility */
+       addit,= 0,arg1,0                /* trap for zero dvr */
+       nop
+       MILLIRET                        /* divisor == 1 */
+       copy    arg0,retreg
+       MILLIRET                        /* divisor == 2 */
+       extru   arg0,30,31,retreg
+       MILLI_BEN($$divU_3)             /* divisor == 3 */
+       nop
+       MILLIRET                        /* divisor == 4 */
+       extru   arg0,29,30,retreg
+       MILLI_BEN($$divU_5)             /* divisor == 5 */
+       nop
+       MILLI_BEN($$divU_6)             /* divisor == 6 */
+       nop
+       MILLI_BEN($$divU_7)             /* divisor == 7 */
+       nop
+       MILLIRET                        /* divisor == 8 */
+       extru   arg0,28,29,retreg
+       MILLI_BEN($$divU_9)             /* divisor == 9 */
+       nop
+       MILLI_BEN($$divU_10)            /* divisor == 10 */
+       nop
+       b       LREF(normal)            /* divisor == 11 */
+       ds      r0,temp,r0              /* set V-bit to 1 */
+       MILLI_BEN($$divU_12)            /* divisor == 12 */
+       nop
+       b       LREF(normal)            /* divisor == 13 */
+       ds      r0,temp,r0              /* set V-bit to 1 */
+       MILLI_BEN($$divU_14)            /* divisor == 14 */
+       nop
+       MILLI_BEN($$divU_15)            /* divisor == 15 */
+       nop
+
+/* Handle the case where the high bit is on in the divisor.
+   Compute:    if( dividend>=divisor) quotient=1; else quotient=0;
+   Note:       dividend>==divisor iff dividend-divisor does not borrow
+   and         not borrow iff carry.  */
+LSYM(big_divisor)
+       sub     arg0,arg1,r0
+       MILLIRET
+       addc    r0,r0,retreg
+       .exit
+       .procend
+       .end
+#endif
+
+#ifdef L_remI
+/* ROUTINE:    $$remI
+
+   DESCRIPTION:
+   .   $$remI returns the remainder of the division of two signed 32-bit
+   .   integers.  The sign of the remainder is the same as the sign of
+   .   the dividend.
+
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   arg1 == divisor
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 = destroyed
+   .   arg1 = destroyed
+   .   ret1 = remainder
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   = undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions:  DIVIDE BY ZERO
+   .   Changes memory at the following places:  NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable
+   .   Does not create a stack frame
+   .   Is usable for internal or external microcode
+
+   DISCUSSION:
+   .   Calls other millicode routines via mrp:  NONE
+   .   Calls other millicode routines:  NONE  */
+
+RDEFINE(tmp,r1)
+RDEFINE(retreg,ret1)
+
+       SUBSPA_MILLI
+       ATTR_MILLI
+       .proc
+       .callinfo millicode
+       .entry
+GSYM($$remI)
+GSYM($$remoI)
+       .export $$remI,MILLICODE
+       .export $$remoI,MILLICODE
+       ldo             -1(arg1),tmp            /*  is there at most one bit set ? */
+       and,<>          arg1,tmp,r0             /*  if not, don't use power of 2 */
+       addi,>          0,arg1,r0               /*  if denominator > 0, use power */
+                                               /*  of 2 */
+       b,n             LREF(neg_denom)
+LSYM(pow2)
+       comb,>,n        0,arg0,LREF(neg_num)    /*  is numerator < 0 ? */
+       and             arg0,tmp,retreg         /*  get the result */
+       MILLIRETN
+LSYM(neg_num)
+       subi            0,arg0,arg0             /*  negate numerator */
+       and             arg0,tmp,retreg         /*  get the result */
+       subi            0,retreg,retreg         /*  negate result */
+       MILLIRETN
+LSYM(neg_denom)
+       addi,<          0,arg1,r0               /*  if arg1 >= 0, it's not power */
+                                               /*  of 2 */
+       b,n             LREF(regular_seq)
+       sub             r0,arg1,tmp             /*  make denominator positive */
+       comb,=,n        arg1,tmp,LREF(regular_seq) /*  test against 0x80000000 and 0 */
+       ldo             -1(tmp),retreg          /*  is there at most one bit set ? */
+       and,=           tmp,retreg,r0           /*  if not, go to regular_seq */
+       b,n             LREF(regular_seq)
+       comb,>,n        0,arg0,LREF(neg_num_2)  /*  if arg0 < 0, negate it  */
+       and             arg0,retreg,retreg
+       MILLIRETN
+LSYM(neg_num_2)
+       subi            0,arg0,tmp              /*  test against 0x80000000 */
+       and             tmp,retreg,retreg
+       subi            0,retreg,retreg
+       MILLIRETN
+LSYM(regular_seq)
+       addit,=         0,arg1,0                /*  trap if div by zero */
+       add,>=          0,arg0,retreg           /*  move dividend, if retreg < 0, */
+       sub             0,retreg,retreg         /*    make it positive */
+       sub             0,arg1, tmp             /*  clear carry,  */
+                                               /*    negate the divisor */
+       ds              0, tmp,0                /*  set V-bit to the comple- */
+                                               /*    ment of the divisor sign */
+       or              0,0, tmp                /*  clear  tmp */
+       add             retreg,retreg,retreg    /*  shift msb bit into carry */
+       ds               tmp,arg1, tmp          /*  1st divide step, if no carry */
+                                               /*    out, msb of quotient = 0 */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+LSYM(t1)
+       ds               tmp,arg1, tmp          /*  2nd divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  3rd divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  4th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  5th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  6th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  7th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  8th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  9th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  10th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  11th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  12th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  13th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  14th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  15th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  16th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  17th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  18th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  19th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  20th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  21st divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  22nd divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  23rd divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  24th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  25th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  26th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  27th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  28th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  29th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  30th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  31st divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  32nd divide step, */
+       addc            retreg,retreg,retreg    /*  shift last bit into retreg */
+       movb,>=,n        tmp,retreg,LREF(finish) /*  branch if pos.  tmp */
+       add,<           arg1,0,0                /*  if arg1 > 0, add arg1 */
+       add,tr           tmp,arg1,retreg        /*    for correcting remainder tmp */
+       sub              tmp,arg1,retreg        /*  else add absolute value arg1 */
+LSYM(finish)
+       add,>=          arg0,0,0                /*  set sign of remainder */
+       sub             0,retreg,retreg         /*    to sign of dividend */
+       MILLIRET
+       nop
+       .exit
+       .procend
+#ifdef milliext
+       .origin 0x00000200
+#endif
+       .end
+#endif
+
+#ifdef L_remU
+/* ROUTINE:    $$remU
+   .   Single precision divide for remainder with unsigned binary integers.
+   .
+   .   The remainder must be dividend-(dividend/divisor)*divisor.
+   .   Divide by zero is trapped.
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   arg1 == divisor
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 =  undefined
+   .   arg1 =  undefined
+   .   ret1 =  remainder
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   =  undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions:  DIVIDE BY ZERO
+   .   Changes memory at the following places:  NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable.
+   .   Does not create a stack frame.
+   .   Suitable for internal or external millicode.
+   .   Assumes the special millicode register conventions.
+
+   DISCUSSION:
+   .   Calls other millicode routines using mrp: NONE
+   .   Calls other millicode routines: NONE  */
+
+
+RDEFINE(temp,r1)
+RDEFINE(rmndr,ret1)    /*  r29 */
+       SUBSPA_MILLI
+       ATTR_MILLI
+       .export $$remU,millicode
+       .proc
+       .callinfo       millicode
+       .entry
+GSYM($$remU)
+       ldo     -1(arg1),temp           /*  is there at most one bit set ? */
+       and,=   arg1,temp,r0            /*  if not, don't use power of 2 */
+       b       LREF(regular_seq)
+       addit,= 0,arg1,r0               /*  trap on div by zero */
+       and     arg0,temp,rmndr         /*  get the result for power of 2 */
+       MILLIRETN
+LSYM(regular_seq)
+       comib,>=,n  0,arg1,LREF(special_case)
+       subi    0,arg1,rmndr            /*  clear carry, negate the divisor */
+       ds      r0,rmndr,r0             /*  set V-bit to 1 */
+       add     arg0,arg0,temp          /*  shift msb bit into carry */
+       ds      r0,arg1,rmndr           /*  1st divide step, if no carry */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  2nd divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  3rd divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  4th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  5th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  6th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  7th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  8th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  9th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  10th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  11th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  12th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  13th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  14th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  15th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  16th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  17th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  18th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  19th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  20th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  21st divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  22nd divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  23rd divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  24th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  25th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  26th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  27th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  28th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  29th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  30th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  31st divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  32nd divide step, */
+       comiclr,<= 0,rmndr,r0
+         add   rmndr,arg1,rmndr        /*  correction */
+       MILLIRETN
+       nop
+
+/* Putting >= on the last DS and deleting COMICLR does not work!  */
+LSYM(special_case)
+       sub,>>= arg0,arg1,rmndr
+         copy  arg0,rmndr
+       MILLIRETN
+       nop
+       .exit
+       .procend
+       .end
+#endif
+
+#ifdef L_div_const
+/* ROUTINE:    $$divI_2
+   .           $$divI_3        $$divU_3
+   .           $$divI_4
+   .           $$divI_5        $$divU_5
+   .           $$divI_6        $$divU_6
+   .           $$divI_7        $$divU_7
+   .           $$divI_8
+   .           $$divI_9        $$divU_9
+   .           $$divI_10       $$divU_10
+   .
+   .           $$divI_12       $$divU_12
+   .
+   .           $$divI_14       $$divU_14
+   .           $$divI_15       $$divU_15
+   .           $$divI_16
+   .           $$divI_17       $$divU_17
+   .
+   .   Divide by selected constants for single precision binary integers.
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 =  undefined
+   .   arg1 =  undefined
+   .   ret1 =  quotient
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   =  undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions: NONE
+   .   Changes memory at the following places:  NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable.
+   .   Does not create a stack frame.
+   .   Suitable for internal or external millicode.
+   .   Assumes the special millicode register conventions.
+
+   DISCUSSION:
+   .   Calls other millicode routines using mrp:  NONE
+   .   Calls other millicode routines:  NONE  */
+
+
+/* TRUNCATED DIVISION BY SMALL INTEGERS
+
+   We are interested in q(x) = floor(x/y), where x >= 0 and y > 0
+   (with y fixed).
+
+   Let a = floor(z/y), for some choice of z.  Note that z will be
+   chosen so that division by z is cheap.
+
+   Let r be the remainder(z/y).  In other words, r = z - ay.
+
+   Now, our method is to choose a value for b such that
+
+   q'(x) = floor((ax+b)/z)
+
+   is equal to q(x) over as large a range of x as possible.  If the
+   two are equal over a sufficiently large range, and if it is easy to
+   form the product (ax), and it is easy to divide by z, then we can
+   perform the division much faster than the general division algorithm.
+
+   So, we want the following to be true:
+
+   .   For x in the following range:
+   .
+   .       ky <= x < (k+1)y
+   .
+   .   implies that
+   .
+   .       k <= (ax+b)/z < (k+1)
+
+   We want to determine b such that this is true for all k in the
+   range {0..K} for some maximum K.
+
+   Since (ax+b) is an increasing function of x, we can take each
+   bound separately to determine the "best" value for b.
+
+   (ax+b)/z < (k+1)           implies
+
+   (a((k+1)y-1)+b < (k+1)z     implies
+
+   b < a + (k+1)(z-ay)        implies
+
+   b < a + (k+1)r
+
+   This needs to be true for all k in the range {0..K}.  In
+   particular, it is true for k = 0 and this leads to a maximum
+   acceptable value for b.
+
+   b < a+r   or   b <= a+r-1
+
+   Taking the other bound, we have
+
+   k <= (ax+b)/z              implies
+
+   k <= (aky+b)/z             implies
+
+   k(z-ay) <= b                       implies
+
+   kr <= b
+
+   Clearly, the largest range for k will be achieved by maximizing b,
+   when r is not zero. When r is zero, then the simplest choice for b
+   is 0.  When r is not 0, set
+
+   .   b = a+r-1
+
+   Now, by construction, q'(x) = floor((ax+b)/z) = q(x) = floor(x/y)
+   for all x in the range:
+
+   .   0 <= x < (K+1)y
+
+   We need to determine what K is.  Of our two bounds,
+
+   .   b < a+(k+1)r    is satisfied for all k >= 0, by construction.
+
+   The other bound is
+
+   .   kr <= b
+
+   This is always true if r = 0.  If r is not 0 (the usual case), then
+   K = floor((a+r-1)/r), is the maximum value for k.
+
+   Therefore, the formula q'(x) = floor((ax+b)/z) yields the correct
+   answer for q(x) = floor(x/y) when x is in the range
+
+   (0,(K+1)y-1)               K = floor((a+r-1)/r)
+
+   To be most useful, we want (K+1)y-1 = (max x) >= 2**32-1 so that
+   the formula for q'(x) yields the correct value of q(x) for all x
+   representable by a single word in HPPA.
+
+   We are also constrained in that computing the product (ax), adding
+   b, and dividing by z must all be done quickly, otherwise we will be
+   better off going through the general algorithm using the DS
+   instruction, which uses approximately 70 cycles.
+
+   For each y, there is a choice of z which satisfies the constraints
+   for (K+1)y >= 2**32.  We may not, however, be able to satisfy the
+   timing constraints for arbitrary y. It seems that z being equal to
+   a power of 2 or a power of 2 minus 1 is as good as we can do, since
+   it minimizes the time to do division by z.  We want the choice of z
+   to also result in a value for (a) that minimizes the computation of
+   the product (ax).  This is best achieved if (a) has a regular bit
+   pattern (so the multiplication can be done with shifts and adds).
+   The value of (a) also needs to be less than 2**32 so the product is
+   always guaranteed to fit in 2 words.
+
+   In actual practice, the following should be done:
+
+   1) For negative x, you should take the absolute value and remember
+   .  the fact so that the result can be negated.  This obviously does
+   .  not apply in the unsigned case.
+   2) For even y, you should factor out the power of 2 that divides y
+   .  and divide x by it.  You can then proceed by dividing by the
+   .  odd factor of y.
+
+   Here is a table of some odd values of y, and corresponding choices
+   for z which are "good".
+
+    y    z       r      a (hex)     max x (hex)
+
+    3  2**32     1     55555555      100000001
+    5  2**32     1     33333333      100000003
+    7  2**24-1   0       249249     (infinite)
+    9  2**24-1   0       1c71c7     (infinite)
+   11  2**20-1   0        1745d     (infinite)
+   13  2**24-1   0       13b13b     (infinite)
+   15  2**32     1     11111111      10000000d
+   17  2**32     1      f0f0f0f      10000000f
+
+   If r is 1, then b = a+r-1 = a.  This simplifies the computation
+   of (ax+b), since you can compute (x+1)(a) instead.  If r is 0,
+   then b = 0 is ok to use which simplifies (ax+b).
+
+   The bit patterns for 55555555, 33333333, and 11111111 are obviously
+   very regular.  The bit patterns for the other values of a above are:
+
+    y     (hex)          (binary)
+
+    7    249249  001001001001001001001001  << regular >>
+    9    1c71c7  000111000111000111000111  << regular >>
+   11     1745d  000000010111010001011101  << irregular >>
+   13    13b13b  000100111011000100111011  << irregular >>
+
+   The bit patterns for (a) corresponding to (y) of 11 and 13 may be
+   too irregular to warrant using this method.
+
+   When z is a power of 2 minus 1, then the division by z is slightly
+   more complicated, involving an iterative solution.
+
+   The code presented here solves division by 1 through 17, except for
+   11 and 13. There are algorithms for both signed and unsigned
+   quantities given.
+
+   TIMINGS (cycles)
+
+   divisor  positive  negative unsigned
+
+   .   1       2          2         2
+   .   2       4          4         2
+   .   3       19        21        19
+   .   4       4          4         2
+   .   5       18        22        19
+   .   6       19        22        19
+   .   8       4          4         2
+   .  10       18        19        17
+   .  12       18        20        18
+   .  15       16        18        16
+   .  16       4          4         2
+   .  17       16        18        16
+
+   Now, the algorithm for 7, 9, and 14 is an iterative one.  That is,
+   a loop body is executed until the tentative quotient is 0.  The
+   number of times the loop body is executed varies depending on the
+   dividend, but is never more than two times. If the dividend is
+   less than the divisor, then the loop body is not executed at all.
+   Each iteration adds 4 cycles to the timings.
+
+   divisor  positive  negative unsigned
+
+   .   7       19+4n    20+4n     20+4n    n = number of iterations
+   .   9       21+4n    22+4n     21+4n
+   .  14       21+4n    22+4n     20+4n
+
+   To give an idea of how the number of iterations varies, here is a
+   table of dividend versus number of iterations when dividing by 7.
+
+   smallest     largest       required
+   dividend    dividend      iterations
+
+   .   0            6              0
+   .   7        0x6ffffff          1
+   0x1000006   0xffffffff          2
+
+   There is some overlap in the range of numbers requiring 1 and 2
+   iterations. */
+
+RDEFINE(t2,r1)
+RDEFINE(x2,arg0)       /*  r26 */
+RDEFINE(t1,arg1)       /*  r25 */
+RDEFINE(x1,ret1)       /*  r29 */
+
+       SUBSPA_MILLI_DIV
+       ATTR_MILLI
+
+       .proc
+       .callinfo       millicode
+       .entry
+/* NONE of these routines require a stack frame
+   ALL of these routines are unwindable from millicode */
+
+GSYM($$divide_by_constant)
+       .export $$divide_by_constant,millicode
+/*  Provides a "nice" label for the code covered by the unwind descriptor
+    for things like gprof.  */
+
+/* DIVISION BY 2 (shift by 1) */
+GSYM($$divI_2)
+       .export         $$divI_2,millicode
+       comclr,>=       arg0,0,0
+       addi            1,arg0,arg0
+       MILLIRET
+       extrs           arg0,30,31,ret1
+
+
+/* DIVISION BY 4 (shift by 2) */
+GSYM($$divI_4)
+       .export         $$divI_4,millicode
+       comclr,>=       arg0,0,0
+       addi            3,arg0,arg0
+       MILLIRET
+       extrs           arg0,29,30,ret1
+
+
+/* DIVISION BY 8 (shift by 3) */
+GSYM($$divI_8)
+       .export         $$divI_8,millicode
+       comclr,>=       arg0,0,0
+       addi            7,arg0,arg0
+       MILLIRET
+       extrs           arg0,28,29,ret1
+
+/* DIVISION BY 16 (shift by 4) */
+GSYM($$divI_16)
+       .export         $$divI_16,millicode
+       comclr,>=       arg0,0,0
+       addi            15,arg0,arg0
+       MILLIRET
+       extrs           arg0,27,28,ret1
+
+/****************************************************************************
+*
+*      DIVISION BY DIVISORS OF FFFFFFFF, and powers of 2 times these
+*
+*      includes 3,5,15,17 and also 6,10,12
+*
+****************************************************************************/
+
+/* DIVISION BY 3 (use z = 2**32; a = 55555555) */
+
+GSYM($$divI_3)
+       .export         $$divI_3,millicode
+       comb,<,N        x2,0,LREF(neg3)
+
+       addi            1,x2,x2         /* this cannot overflow */
+       extru           x2,1,2,x1       /* multiply by 5 to get started */
+       sh2add          x2,x2,x2
+       b               LREF(pos)
+       addc            x1,0,x1
+
+LSYM(neg3)
+       subi            1,x2,x2         /* this cannot overflow */
+       extru           x2,1,2,x1       /* multiply by 5 to get started */
+       sh2add          x2,x2,x2
+       b               LREF(neg)
+       addc            x1,0,x1
+
+GSYM($$divU_3)
+       .export         $$divU_3,millicode
+       addi            1,x2,x2         /* this CAN overflow */
+       addc            0,0,x1
+       shd             x1,x2,30,t1     /* multiply by 5 to get started */
+       sh2add          x2,x2,x2
+       b               LREF(pos)
+       addc            x1,t1,x1
+
+/* DIVISION BY 5 (use z = 2**32; a = 33333333) */
+
+GSYM($$divI_5)
+       .export         $$divI_5,millicode
+       comb,<,N        x2,0,LREF(neg5)
+
+       addi            3,x2,t1         /* this cannot overflow */
+       sh1add          x2,t1,x2        /* multiply by 3 to get started */
+       b               LREF(pos)
+       addc            0,0,x1
+
+LSYM(neg5)
+       sub             0,x2,x2         /* negate x2                    */
+       addi            1,x2,x2         /* this cannot overflow */
+       shd             0,x2,31,x1      /* get top bit (can be 1)       */
+       sh1add          x2,x2,x2        /* multiply by 3 to get started */
+       b               LREF(neg)
+       addc            x1,0,x1
+
+GSYM($$divU_5)
+       .export         $$divU_5,millicode
+       addi            1,x2,x2         /* this CAN overflow */
+       addc            0,0,x1
+       shd             x1,x2,31,t1     /* multiply by 3 to get started */
+       sh1add          x2,x2,x2
+       b               LREF(pos)
+       addc            t1,x1,x1
+
+/* DIVISION BY 6 (shift to divide by 2 then divide by 3) */
+GSYM($$divI_6)
+       .export         $$divI_6,millicode
+       comb,<,N        x2,0,LREF(neg6)
+       extru           x2,30,31,x2     /* divide by 2                  */
+       addi            5,x2,t1         /* compute 5*(x2+1) = 5*x2+5    */
+       sh2add          x2,t1,x2        /* multiply by 5 to get started */
+       b               LREF(pos)
+       addc            0,0,x1
+
+LSYM(neg6)
+       subi            2,x2,x2         /* negate, divide by 2, and add 1 */
+                                       /* negation and adding 1 are done */
+                                       /* at the same time by the SUBI   */
+       extru           x2,30,31,x2
+       shd             0,x2,30,x1
+       sh2add          x2,x2,x2        /* multiply by 5 to get started */
+       b               LREF(neg)
+       addc            x1,0,x1
+
+GSYM($$divU_6)
+       .export         $$divU_6,millicode
+       extru           x2,30,31,x2     /* divide by 2 */
+       addi            1,x2,x2         /* cannot carry */
+       shd             0,x2,30,x1      /* multiply by 5 to get started */
+       sh2add          x2,x2,x2
+       b               LREF(pos)
+       addc            x1,0,x1
+
+/* DIVISION BY 10 (shift to divide by 2 then divide by 5) */
+GSYM($$divU_10)
+       .export         $$divU_10,millicode
+       extru           x2,30,31,x2     /* divide by 2 */
+       addi            3,x2,t1         /* compute 3*(x2+1) = (3*x2)+3  */
+       sh1add          x2,t1,x2        /* multiply by 3 to get started */
+       addc            0,0,x1
+LSYM(pos)
+       shd             x1,x2,28,t1     /* multiply by 0x11 */
+       shd             x2,0,28,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+LSYM(pos_for_17)
+       shd             x1,x2,24,t1     /* multiply by 0x101 */
+       shd             x2,0,24,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+
+       shd             x1,x2,16,t1     /* multiply by 0x10001 */
+       shd             x2,0,16,t2
+       add             x2,t2,x2
+       MILLIRET
+       addc            x1,t1,x1
+
+GSYM($$divI_10)
+       .export         $$divI_10,millicode
+       comb,<          x2,0,LREF(neg10)
+       copy            0,x1
+       extru           x2,30,31,x2     /* divide by 2 */
+       addib,TR        1,x2,LREF(pos)  /* add 1 (cannot overflow)     */
+       sh1add          x2,x2,x2        /* multiply by 3 to get started */
+
+LSYM(neg10)
+       subi            2,x2,x2         /* negate, divide by 2, and add 1 */
+                                       /* negation and adding 1 are done */
+                                       /* at the same time by the SUBI   */
+       extru           x2,30,31,x2
+       sh1add          x2,x2,x2        /* multiply by 3 to get started */
+LSYM(neg)
+       shd             x1,x2,28,t1     /* multiply by 0x11 */
+       shd             x2,0,28,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+LSYM(neg_for_17)
+       shd             x1,x2,24,t1     /* multiply by 0x101 */
+       shd             x2,0,24,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+
+       shd             x1,x2,16,t1     /* multiply by 0x10001 */
+       shd             x2,0,16,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+       MILLIRET
+       sub             0,x1,x1
+
+/* DIVISION BY 12 (shift to divide by 4 then divide by 3) */
+GSYM($$divI_12)
+       .export         $$divI_12,millicode
+       comb,<          x2,0,LREF(neg12)
+       copy            0,x1
+       extru           x2,29,30,x2     /* divide by 4                  */
+       addib,tr        1,x2,LREF(pos)  /* compute 5*(x2+1) = 5*x2+5    */
+       sh2add          x2,x2,x2        /* multiply by 5 to get started */
+
+LSYM(neg12)
+       subi            4,x2,x2         /* negate, divide by 4, and add 1 */
+                                       /* negation and adding 1 are done */
+                                       /* at the same time by the SUBI   */
+       extru           x2,29,30,x2
+       b               LREF(neg)
+       sh2add          x2,x2,x2        /* multiply by 5 to get started */
+
+GSYM($$divU_12)
+       .export         $$divU_12,millicode
+       extru           x2,29,30,x2     /* divide by 4   */
+       addi            5,x2,t1         /* cannot carry */
+       sh2add          x2,t1,x2        /* multiply by 5 to get started */
+       b               LREF(pos)
+       addc            0,0,x1
+
+/* DIVISION BY 15 (use z = 2**32; a = 11111111) */
+GSYM($$divI_15)
+       .export         $$divI_15,millicode
+       comb,<          x2,0,LREF(neg15)
+       copy            0,x1
+       addib,tr        1,x2,LREF(pos)+4
+       shd             x1,x2,28,t1
+
+LSYM(neg15)
+       b               LREF(neg)
+       subi            1,x2,x2
+
+GSYM($$divU_15)
+       .export         $$divU_15,millicode
+       addi            1,x2,x2         /* this CAN overflow */
+       b               LREF(pos)
+       addc            0,0,x1
+
+/* DIVISION BY 17 (use z = 2**32; a =  f0f0f0f) */
+GSYM($$divI_17)
+       .export         $$divI_17,millicode
+       comb,<,n        x2,0,LREF(neg17)
+       addi            1,x2,x2         /* this cannot overflow */
+       shd             0,x2,28,t1      /* multiply by 0xf to get started */
+       shd             x2,0,28,t2
+       sub             t2,x2,x2
+       b               LREF(pos_for_17)
+       subb            t1,0,x1
+
+LSYM(neg17)
+       subi            1,x2,x2         /* this cannot overflow */
+       shd             0,x2,28,t1      /* multiply by 0xf to get started */
+       shd             x2,0,28,t2
+       sub             t2,x2,x2
+       b               LREF(neg_for_17)
+       subb            t1,0,x1
+
+GSYM($$divU_17)
+       .export         $$divU_17,millicode
+       addi            1,x2,x2         /* this CAN overflow */
+       addc            0,0,x1
+       shd             x1,x2,28,t1     /* multiply by 0xf to get started */
+LSYM(u17)
+       shd             x2,0,28,t2
+       sub             t2,x2,x2
+       b               LREF(pos_for_17)
+       subb            t1,x1,x1
+
+
+/* DIVISION BY DIVISORS OF FFFFFF, and powers of 2 times these
+   includes 7,9 and also 14
+
+
+   z = 2**24-1
+   r = z mod x = 0
+
+   so choose b = 0
+
+   Also, in order to divide by z = 2**24-1, we approximate by dividing
+   by (z+1) = 2**24 (which is easy), and then correcting.
+
+   (ax) = (z+1)q' + r
+   .   = zq' + (q'+r)
+
+   So to compute (ax)/z, compute q' = (ax)/(z+1) and r = (ax) mod (z+1)
+   Then the true remainder of (ax)/z is (q'+r).  Repeat the process
+   with this new remainder, adding the tentative quotients together,
+   until a tentative quotient is 0 (and then we are done).  There is
+   one last correction to be done.  It is possible that (q'+r) = z.
+   If so, then (q'+r)/(z+1) = 0 and it looks like we are done. But,
+   in fact, we need to add 1 more to the quotient.  Now, it turns
+   out that this happens if and only if the original value x is
+   an exact multiple of y.  So, to avoid a three instruction test at
+   the end, instead use 1 instruction to add 1 to x at the beginning.  */
+
+/* DIVISION BY 7 (use z = 2**24-1; a = 249249) */
+GSYM($$divI_7)
+       .export         $$divI_7,millicode
+       comb,<,n        x2,0,LREF(neg7)
+LSYM(7)
+       addi            1,x2,x2         /* cannot overflow */
+       shd             0,x2,29,x1
+       sh3add          x2,x2,x2
+       addc            x1,0,x1
+LSYM(pos7)
+       shd             x1,x2,26,t1
+       shd             x2,0,26,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+
+       shd             x1,x2,20,t1
+       shd             x2,0,20,t2
+       add             x2,t2,x2
+       addc            x1,t1,t1
+
+       /* computed <t1,x2>.  Now divide it by (2**24 - 1)      */
+
+       copy            0,x1
+       shd,=           t1,x2,24,t1     /* tentative quotient  */
+LSYM(1)
+       addb,tr         t1,x1,LREF(2)   /* add to previous quotient   */
+       extru           x2,31,24,x2     /* new remainder (unadjusted) */
+
+       MILLIRETN
+
+LSYM(2)
+       addb,tr         t1,x2,LREF(1)   /* adjust remainder */
+       extru,=         x2,7,8,t1       /* new quotient     */
+
+LSYM(neg7)
+       subi            1,x2,x2         /* negate x2 and add 1 */
+LSYM(8)
+       shd             0,x2,29,x1
+       sh3add          x2,x2,x2
+       addc            x1,0,x1
+
+LSYM(neg7_shift)
+       shd             x1,x2,26,t1
+       shd             x2,0,26,t2
+       add             x2,t2,x2
+       addc            x1,t1,x1
+
+       shd             x1,x2,20,t1
+       shd             x2,0,20,t2
+       add             x2,t2,x2
+       addc            x1,t1,t1
+
+       /* computed <t1,x2>.  Now divide it by (2**24 - 1)      */
+
+       copy            0,x1
+       shd,=           t1,x2,24,t1     /* tentative quotient  */
+LSYM(3)
+       addb,tr         t1,x1,LREF(4)   /* add to previous quotient   */
+       extru           x2,31,24,x2     /* new remainder (unadjusted) */
+
+       MILLIRET
+       sub             0,x1,x1         /* negate result    */
+
+LSYM(4)
+       addb,tr         t1,x2,LREF(3)   /* adjust remainder */
+       extru,=         x2,7,8,t1       /* new quotient     */
+
+GSYM($$divU_7)
+       .export         $$divU_7,millicode
+       addi            1,x2,x2         /* can carry */
+       addc            0,0,x1
+       shd             x1,x2,29,t1
+       sh3add          x2,x2,x2
+       b               LREF(pos7)
+       addc            t1,x1,x1
+
+/* DIVISION BY 9 (use z = 2**24-1; a = 1c71c7) */
+GSYM($$divI_9)
+       .export         $$divI_9,millicode
+       comb,<,n        x2,0,LREF(neg9)
+       addi            1,x2,x2         /* cannot overflow */
+       shd             0,x2,29,t1
+       shd             x2,0,29,t2
+       sub             t2,x2,x2
+       b               LREF(pos7)
+       subb            t1,0,x1
+
+LSYM(neg9)
+       subi            1,x2,x2         /* negate and add 1 */
+       shd             0,x2,29,t1
+       shd             x2,0,29,t2
+       sub             t2,x2,x2
+       b               LREF(neg7_shift)
+       subb            t1,0,x1
+
+GSYM($$divU_9)
+       .export         $$divU_9,millicode
+       addi            1,x2,x2         /* can carry */
+       addc            0,0,x1
+       shd             x1,x2,29,t1
+       shd             x2,0,29,t2
+       sub             t2,x2,x2
+       b               LREF(pos7)
+       subb            t1,x1,x1
+
+/* DIVISION BY 14 (shift to divide by 2 then divide by 7) */
+GSYM($$divI_14)
+       .export         $$divI_14,millicode
+       comb,<,n        x2,0,LREF(neg14)
+GSYM($$divU_14)
+       .export         $$divU_14,millicode
+       b               LREF(7)         /* go to 7 case */
+       extru           x2,30,31,x2     /* divide by 2  */
+
+LSYM(neg14)
+       subi            2,x2,x2         /* negate (and add 2) */
+       b               LREF(8)
+       extru           x2,30,31,x2     /* divide by 2        */
+       .exit
+       .procend
+       .end
+#endif
+
+#ifdef L_mulI
+/* VERSION "@(#)$$mulI $ Revision: 12.4 $ $ Date: 94/03/17 17:18:51 $" */
+/******************************************************************************
+This routine is used on PA2.0 processors when gcc -mno-fpregs is used
+
+ROUTINE:       $$mulI
+
+
+DESCRIPTION:   
+
+       $$mulI multiplies two single word integers, giving a single 
+       word result.  
+
+
+INPUT REGISTERS:
+
+       arg0 = Operand 1
+       arg1 = Operand 2
+       r31  == return pc
+       sr0  == return space when called externally 
+
+
+OUTPUT REGISTERS:
+
+       arg0 = undefined
+       arg1 = undefined
+       ret1 = result 
+
+OTHER REGISTERS AFFECTED:
+
+       r1   = undefined
+
+SIDE EFFECTS:
+
+       Causes a trap under the following conditions:  NONE
+       Changes memory at the following places:  NONE
+
+PERMISSIBLE CONTEXT:
+
+       Unwindable
+       Does not create a stack frame
+       Is usable for internal or external microcode
+
+DISCUSSION:
+
+       Calls other millicode routines via mrp:  NONE
+       Calls other millicode routines:  NONE
+
+***************************************************************************/
+
+
+#define        a0      %arg0
+#define        a1      %arg1
+#define        t0      %r1
+#define        r       %ret1
+
+#define        a0__128a0       zdep    a0,24,25,a0
+#define        a0__256a0       zdep    a0,23,24,a0
+#define        a1_ne_0_b_l0    comb,<> a1,0,LREF(l0)
+#define        a1_ne_0_b_l1    comb,<> a1,0,LREF(l1)
+#define        a1_ne_0_b_l2    comb,<> a1,0,LREF(l2)
+#define        b_n_ret_t0      b,n     LREF(ret_t0)
+#define        b_e_shift       b       LREF(e_shift)
+#define        b_e_t0ma0       b       LREF(e_t0ma0)
+#define        b_e_t0          b       LREF(e_t0)
+#define        b_e_t0a0        b       LREF(e_t0a0)
+#define        b_e_t02a0       b       LREF(e_t02a0)
+#define        b_e_t04a0       b       LREF(e_t04a0)
+#define        b_e_2t0         b       LREF(e_2t0)
+#define        b_e_2t0a0       b       LREF(e_2t0a0)
+#define        b_e_2t04a0      b       LREF(e2t04a0)
+#define        b_e_3t0         b       LREF(e_3t0)
+#define        b_e_4t0         b       LREF(e_4t0)
+#define        b_e_4t0a0       b       LREF(e_4t0a0)
+#define        b_e_4t08a0      b       LREF(e4t08a0)
+#define        b_e_5t0         b       LREF(e_5t0)
+#define        b_e_8t0         b       LREF(e_8t0)
+#define        b_e_8t0a0       b       LREF(e_8t0a0)
+#define        r__r_a0         add     r,a0,r
+#define        r__r_2a0        sh1add  a0,r,r
+#define        r__r_4a0        sh2add  a0,r,r
+#define        r__r_8a0        sh3add  a0,r,r
+#define        r__r_t0         add     r,t0,r
+#define        r__r_2t0        sh1add  t0,r,r
+#define        r__r_4t0        sh2add  t0,r,r
+#define        r__r_8t0        sh3add  t0,r,r
+#define        t0__3a0         sh1add  a0,a0,t0
+#define        t0__4a0         sh2add  a0,0,t0
+#define        t0__5a0         sh2add  a0,a0,t0
+#define        t0__8a0         sh3add  a0,0,t0
+#define        t0__9a0         sh3add  a0,a0,t0
+#define        t0__16a0        zdep    a0,27,28,t0
+#define        t0__32a0        zdep    a0,26,27,t0
+#define        t0__64a0        zdep    a0,25,26,t0
+#define        t0__128a0       zdep    a0,24,25,t0
+#define        t0__t0ma0       sub     t0,a0,t0
+#define        t0__t0_a0       add     t0,a0,t0
+#define        t0__t0_2a0      sh1add  a0,t0,t0
+#define        t0__t0_4a0      sh2add  a0,t0,t0
+#define        t0__t0_8a0      sh3add  a0,t0,t0
+#define        t0__2t0_a0      sh1add  t0,a0,t0
+#define        t0__3t0         sh1add  t0,t0,t0
+#define        t0__4t0         sh2add  t0,0,t0
+#define        t0__4t0_a0      sh2add  t0,a0,t0
+#define        t0__5t0         sh2add  t0,t0,t0
+#define        t0__8t0         sh3add  t0,0,t0
+#define        t0__8t0_a0      sh3add  t0,a0,t0
+#define        t0__9t0         sh3add  t0,t0,t0
+#define        t0__16t0        zdep    t0,27,28,t0
+#define        t0__32t0        zdep    t0,26,27,t0
+#define        t0__256a0       zdep    a0,23,24,t0
+
+
+       SUBSPA_MILLI
+       ATTR_MILLI
+       .align 16
+       .proc
+       .callinfo millicode
+       .export $$mulI,millicode
+GSYM($$mulI)   
+       combt,<<=       a1,a0,LREF(l4)  /* swap args if unsigned a1>a0 */
+       copy            0,r             /* zero out the result */
+       xor             a0,a1,a0        /* swap a0 & a1 using the */
+       xor             a0,a1,a1        /*  old xor trick */
+       xor             a0,a1,a0
+LSYM(l4)
+       combt,<=        0,a0,LREF(l3)           /* if a0>=0 then proceed like unsigned */
+       zdep            a1,30,8,t0      /* t0 = (a1&0xff)<<1 ********* */
+       sub,>           0,a1,t0         /* otherwise negate both and */
+       combt,<=,n      a0,t0,LREF(l2)  /*  swap back if |a0|<|a1| */
+       sub             0,a0,a1
+       movb,tr,n       t0,a0,LREF(l2)  /* 10th inst.  */
+
+LSYM(l0)       r__r_t0                         /* add in this partial product */
+LSYM(l1)       a0__256a0                       /* a0 <<= 8 ****************** */
+LSYM(l2)       zdep            a1,30,8,t0      /* t0 = (a1&0xff)<<1 ********* */
+LSYM(l3)       blr             t0,0            /* case on these 8 bits ****** */
+               extru           a1,23,24,a1     /* a1 >>= 8 ****************** */
+
+/*16 insts before this.  */
+/*                       a0 <<= 8 ************************** */
+LSYM(x0)       a1_ne_0_b_l2    ! a0__256a0     ! MILLIRETN     ! nop
+LSYM(x1)       a1_ne_0_b_l1    ! r__r_a0       ! MILLIRETN     ! nop
+LSYM(x2)       a1_ne_0_b_l1    ! r__r_2a0      ! MILLIRETN     ! nop
+LSYM(x3)       a1_ne_0_b_l0    ! t0__3a0       ! MILLIRET      ! r__r_t0
+LSYM(x4)       a1_ne_0_b_l1    ! r__r_4a0      ! MILLIRETN     ! nop
+LSYM(x5)       a1_ne_0_b_l0    ! t0__5a0       ! MILLIRET      ! r__r_t0
+LSYM(x6)       t0__3a0         ! a1_ne_0_b_l1  ! r__r_2t0      ! MILLIRETN
+LSYM(x7)       t0__3a0         ! a1_ne_0_b_l0  ! r__r_4a0      ! b_n_ret_t0
+LSYM(x8)       a1_ne_0_b_l1    ! r__r_8a0      ! MILLIRETN     ! nop
+LSYM(x9)       a1_ne_0_b_l0    ! t0__9a0       ! MILLIRET      ! r__r_t0
+LSYM(x10)      t0__5a0         ! a1_ne_0_b_l1  ! r__r_2t0      ! MILLIRETN
+LSYM(x11)      t0__3a0         ! a1_ne_0_b_l0  ! r__r_8a0      ! b_n_ret_t0
+LSYM(x12)      t0__3a0         ! a1_ne_0_b_l1  ! r__r_4t0      ! MILLIRETN
+LSYM(x13)      t0__5a0         ! a1_ne_0_b_l0  ! r__r_8a0      ! b_n_ret_t0
+LSYM(x14)      t0__3a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x15)      t0__5a0         ! a1_ne_0_b_l0  ! t0__3t0       ! b_n_ret_t0
+LSYM(x16)      t0__16a0        ! a1_ne_0_b_l1  ! r__r_t0       ! MILLIRETN
+LSYM(x17)      t0__9a0         ! a1_ne_0_b_l0  ! t0__t0_8a0    ! b_n_ret_t0
+LSYM(x18)      t0__9a0         ! a1_ne_0_b_l1  ! r__r_2t0      ! MILLIRETN
+LSYM(x19)      t0__9a0         ! a1_ne_0_b_l0  ! t0__2t0_a0    ! b_n_ret_t0
+LSYM(x20)      t0__5a0         ! a1_ne_0_b_l1  ! r__r_4t0      ! MILLIRETN
+LSYM(x21)      t0__5a0         ! a1_ne_0_b_l0  ! t0__4t0_a0    ! b_n_ret_t0
+LSYM(x22)      t0__5a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x23)      t0__5a0         ! t0__2t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x24)      t0__3a0         ! a1_ne_0_b_l1  ! r__r_8t0      ! MILLIRETN
+LSYM(x25)      t0__5a0         ! a1_ne_0_b_l0  ! t0__5t0       ! b_n_ret_t0
+LSYM(x26)      t0__3a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x27)      t0__3a0         ! a1_ne_0_b_l0  ! t0__9t0       ! b_n_ret_t0
+LSYM(x28)      t0__3a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x29)      t0__3a0         ! t0__2t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x30)      t0__5a0         ! t0__3t0       ! b_e_shift     ! r__r_2t0
+LSYM(x31)      t0__32a0        ! a1_ne_0_b_l0  ! t0__t0ma0     ! b_n_ret_t0
+LSYM(x32)      t0__32a0        ! a1_ne_0_b_l1  ! r__r_t0       ! MILLIRETN
+LSYM(x33)      t0__8a0         ! a1_ne_0_b_l0  ! t0__4t0_a0    ! b_n_ret_t0
+LSYM(x34)      t0__16a0        ! t0__t0_a0     ! b_e_shift     ! r__r_2t0
+LSYM(x35)      t0__9a0         ! t0__3t0       ! b_e_t0        ! t0__t0_8a0
+LSYM(x36)      t0__9a0         ! a1_ne_0_b_l1  ! r__r_4t0      ! MILLIRETN
+LSYM(x37)      t0__9a0         ! a1_ne_0_b_l0  ! t0__4t0_a0    ! b_n_ret_t0
+LSYM(x38)      t0__9a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x39)      t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x40)      t0__5a0         ! a1_ne_0_b_l1  ! r__r_8t0      ! MILLIRETN
+LSYM(x41)      t0__5a0         ! a1_ne_0_b_l0  ! t0__8t0_a0    ! b_n_ret_t0
+LSYM(x42)      t0__5a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x43)      t0__5a0         ! t0__4t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x44)      t0__5a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x45)      t0__9a0         ! a1_ne_0_b_l0  ! t0__5t0       ! b_n_ret_t0
+LSYM(x46)      t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__t0_a0
+LSYM(x47)      t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__t0_2a0
+LSYM(x48)      t0__3a0         ! a1_ne_0_b_l0  ! t0__16t0      ! b_n_ret_t0
+LSYM(x49)      t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__t0_4a0
+LSYM(x50)      t0__5a0         ! t0__5t0       ! b_e_shift     ! r__r_2t0
+LSYM(x51)      t0__9a0         ! t0__t0_8a0    ! b_e_t0        ! t0__3t0
+LSYM(x52)      t0__3a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x53)      t0__3a0         ! t0__4t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x54)      t0__9a0         ! t0__3t0       ! b_e_shift     ! r__r_2t0
+LSYM(x55)      t0__9a0         ! t0__3t0       ! b_e_t0        ! t0__2t0_a0
+LSYM(x56)      t0__3a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x57)      t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x58)      t0__3a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__4t0_a0
+LSYM(x59)      t0__9a0         ! t0__2t0_a0    ! b_e_t02a0     ! t0__3t0
+LSYM(x60)      t0__5a0         ! t0__3t0       ! b_e_shift     ! r__r_4t0
+LSYM(x61)      t0__5a0         ! t0__3t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x62)      t0__32a0        ! t0__t0ma0     ! b_e_shift     ! r__r_2t0
+LSYM(x63)      t0__64a0        ! a1_ne_0_b_l0  ! t0__t0ma0     ! b_n_ret_t0
+LSYM(x64)      t0__64a0        ! a1_ne_0_b_l1  ! r__r_t0       ! MILLIRETN
+LSYM(x65)      t0__8a0         ! a1_ne_0_b_l0  ! t0__8t0_a0    ! b_n_ret_t0
+LSYM(x66)      t0__32a0        ! t0__t0_a0     ! b_e_shift     ! r__r_2t0
+LSYM(x67)      t0__8a0         ! t0__4t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x68)      t0__8a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x69)      t0__8a0         ! t0__2t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x70)      t0__64a0        ! t0__t0_4a0    ! b_e_t0        ! t0__t0_2a0
+LSYM(x71)      t0__9a0         ! t0__8t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x72)      t0__9a0         ! a1_ne_0_b_l1  ! r__r_8t0      ! MILLIRETN
+LSYM(x73)      t0__9a0         ! t0__8t0_a0    ! b_e_shift     ! r__r_t0
+LSYM(x74)      t0__9a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x75)      t0__9a0         ! t0__4t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x76)      t0__9a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x77)      t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x78)      t0__9a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x79)      t0__16a0        ! t0__5t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x80)      t0__16a0        ! t0__5t0       ! b_e_shift     ! r__r_t0
+LSYM(x81)      t0__9a0         ! t0__9t0       ! b_e_shift     ! r__r_t0
+LSYM(x82)      t0__5a0         ! t0__8t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x83)      t0__5a0         ! t0__8t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x84)      t0__5a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x85)      t0__8a0         ! t0__2t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x86)      t0__5a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x87)      t0__9a0         ! t0__9t0       ! b_e_t02a0     ! t0__t0_4a0
+LSYM(x88)      t0__5a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x89)      t0__5a0         ! t0__2t0_a0    ! b_e_t0        ! t0__8t0_a0
+LSYM(x90)      t0__9a0         ! t0__5t0       ! b_e_shift     ! r__r_2t0
+LSYM(x91)      t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__2t0_a0
+LSYM(x92)      t0__5a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__2t0_a0
+LSYM(x93)      t0__32a0        ! t0__t0ma0     ! b_e_t0        ! t0__3t0
+LSYM(x94)      t0__9a0         ! t0__5t0       ! b_e_2t0       ! t0__t0_2a0
+LSYM(x95)      t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x96)      t0__8a0         ! t0__3t0       ! b_e_shift     ! r__r_4t0
+LSYM(x97)      t0__8a0         ! t0__3t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x98)      t0__32a0        ! t0__3t0       ! b_e_t0        ! t0__t0_2a0
+LSYM(x99)      t0__8a0         ! t0__4t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x100)     t0__5a0         ! t0__5t0       ! b_e_shift     ! r__r_4t0
+LSYM(x101)     t0__5a0         ! t0__5t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x102)     t0__32a0        ! t0__t0_2a0    ! b_e_t0        ! t0__3t0
+LSYM(x103)     t0__5a0         ! t0__5t0       ! b_e_t02a0     ! t0__4t0_a0
+LSYM(x104)     t0__3a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x105)     t0__5a0         ! t0__4t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x106)     t0__3a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__4t0_a0
+LSYM(x107)     t0__9a0         ! t0__t0_4a0    ! b_e_t02a0     ! t0__8t0_a0
+LSYM(x108)     t0__9a0         ! t0__3t0       ! b_e_shift     ! r__r_4t0
+LSYM(x109)     t0__9a0         ! t0__3t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x110)     t0__9a0         ! t0__3t0       ! b_e_2t0       ! t0__2t0_a0
+LSYM(x111)     t0__9a0         ! t0__4t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x112)     t0__3a0         ! t0__2t0_a0    ! b_e_t0        ! t0__16t0
+LSYM(x113)     t0__9a0         ! t0__4t0_a0    ! b_e_t02a0     ! t0__3t0
+LSYM(x114)     t0__9a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__3t0
+LSYM(x115)     t0__9a0         ! t0__2t0_a0    ! b_e_2t0a0     ! t0__3t0
+LSYM(x116)     t0__3a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__4t0_a0
+LSYM(x117)     t0__3a0         ! t0__4t0_a0    ! b_e_t0        ! t0__9t0
+LSYM(x118)     t0__3a0         ! t0__4t0_a0    ! b_e_t0a0      ! t0__9t0
+LSYM(x119)     t0__3a0         ! t0__4t0_a0    ! b_e_t02a0     ! t0__9t0
+LSYM(x120)     t0__5a0         ! t0__3t0       ! b_e_shift     ! r__r_8t0
+LSYM(x121)     t0__5a0         ! t0__3t0       ! b_e_t0        ! t0__8t0_a0
+LSYM(x122)     t0__5a0         ! t0__3t0       ! b_e_2t0       ! t0__4t0_a0
+LSYM(x123)     t0__5a0         ! t0__8t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x124)     t0__32a0        ! t0__t0ma0     ! b_e_shift     ! r__r_4t0
+LSYM(x125)     t0__5a0         ! t0__5t0       ! b_e_t0        ! t0__5t0
+LSYM(x126)     t0__64a0        ! t0__t0ma0     ! b_e_shift     ! r__r_2t0
+LSYM(x127)     t0__128a0       ! a1_ne_0_b_l0  ! t0__t0ma0     ! b_n_ret_t0
+LSYM(x128)     t0__128a0       ! a1_ne_0_b_l1  ! r__r_t0       ! MILLIRETN
+LSYM(x129)     t0__128a0       ! a1_ne_0_b_l0  ! t0__t0_a0     ! b_n_ret_t0
+LSYM(x130)     t0__64a0        ! t0__t0_a0     ! b_e_shift     ! r__r_2t0
+LSYM(x131)     t0__8a0         ! t0__8t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x132)     t0__8a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x133)     t0__8a0         ! t0__4t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x134)     t0__8a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x135)     t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__3t0
+LSYM(x136)     t0__8a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x137)     t0__8a0         ! t0__2t0_a0    ! b_e_t0        ! t0__8t0_a0
+LSYM(x138)     t0__8a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__4t0_a0
+LSYM(x139)     t0__8a0         ! t0__2t0_a0    ! b_e_2t0a0     ! t0__4t0_a0
+LSYM(x140)     t0__3a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__5t0
+LSYM(x141)     t0__8a0         ! t0__2t0_a0    ! b_e_4t0a0     ! t0__2t0_a0
+LSYM(x142)     t0__9a0         ! t0__8t0       ! b_e_2t0       ! t0__t0ma0
+LSYM(x143)     t0__16a0        ! t0__9t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x144)     t0__9a0         ! t0__8t0       ! b_e_shift     ! r__r_2t0
+LSYM(x145)     t0__9a0         ! t0__8t0       ! b_e_t0        ! t0__2t0_a0
+LSYM(x146)     t0__9a0         ! t0__8t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x147)     t0__9a0         ! t0__8t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x148)     t0__9a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x149)     t0__9a0         ! t0__4t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x150)     t0__9a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x151)     t0__9a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__2t0_a0
+LSYM(x152)     t0__9a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x153)     t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__8t0_a0
+LSYM(x154)     t0__9a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__4t0_a0
+LSYM(x155)     t0__32a0        ! t0__t0ma0     ! b_e_t0        ! t0__5t0
+LSYM(x156)     t0__9a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__2t0_a0
+LSYM(x157)     t0__32a0        ! t0__t0ma0     ! b_e_t02a0     ! t0__5t0
+LSYM(x158)     t0__16a0        ! t0__5t0       ! b_e_2t0       ! t0__t0ma0
+LSYM(x159)     t0__32a0        ! t0__5t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x160)     t0__5a0         ! t0__4t0       ! b_e_shift     ! r__r_8t0
+LSYM(x161)     t0__8a0         ! t0__5t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x162)     t0__9a0         ! t0__9t0       ! b_e_shift     ! r__r_2t0
+LSYM(x163)     t0__9a0         ! t0__9t0       ! b_e_t0        ! t0__2t0_a0
+LSYM(x164)     t0__5a0         ! t0__8t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x165)     t0__8a0         ! t0__4t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x166)     t0__5a0         ! t0__8t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x167)     t0__5a0         ! t0__8t0_a0    ! b_e_2t0a0     ! t0__2t0_a0
+LSYM(x168)     t0__5a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x169)     t0__5a0         ! t0__4t0_a0    ! b_e_t0        ! t0__8t0_a0
+LSYM(x170)     t0__32a0        ! t0__t0_2a0    ! b_e_t0        ! t0__5t0
+LSYM(x171)     t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__9t0
+LSYM(x172)     t0__5a0         ! t0__4t0_a0    ! b_e_4t0       ! t0__2t0_a0
+LSYM(x173)     t0__9a0         ! t0__2t0_a0    ! b_e_t02a0     ! t0__9t0
+LSYM(x174)     t0__32a0        ! t0__t0_2a0    ! b_e_t04a0     ! t0__5t0
+LSYM(x175)     t0__8a0         ! t0__2t0_a0    ! b_e_5t0       ! t0__2t0_a0
+LSYM(x176)     t0__5a0         ! t0__4t0_a0    ! b_e_8t0       ! t0__t0_a0
+LSYM(x177)     t0__5a0         ! t0__4t0_a0    ! b_e_8t0a0     ! t0__t0_a0
+LSYM(x178)     t0__5a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__8t0_a0
+LSYM(x179)     t0__5a0         ! t0__2t0_a0    ! b_e_2t0a0     ! t0__8t0_a0
+LSYM(x180)     t0__9a0         ! t0__5t0       ! b_e_shift     ! r__r_4t0
+LSYM(x181)     t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x182)     t0__9a0         ! t0__5t0       ! b_e_2t0       ! t0__2t0_a0
+LSYM(x183)     t0__9a0         ! t0__5t0       ! b_e_2t0a0     ! t0__2t0_a0
+LSYM(x184)     t0__5a0         ! t0__9t0       ! b_e_4t0       ! t0__t0_a0
+LSYM(x185)     t0__9a0         ! t0__4t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x186)     t0__32a0        ! t0__t0ma0     ! b_e_2t0       ! t0__3t0
+LSYM(x187)     t0__9a0         ! t0__4t0_a0    ! b_e_t02a0     ! t0__5t0
+LSYM(x188)     t0__9a0         ! t0__5t0       ! b_e_4t0       ! t0__t0_2a0
+LSYM(x189)     t0__5a0         ! t0__4t0_a0    ! b_e_t0        ! t0__9t0
+LSYM(x190)     t0__9a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__5t0
+LSYM(x191)     t0__64a0        ! t0__3t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x192)     t0__8a0         ! t0__3t0       ! b_e_shift     ! r__r_8t0
+LSYM(x193)     t0__8a0         ! t0__3t0       ! b_e_t0        ! t0__8t0_a0
+LSYM(x194)     t0__8a0         ! t0__3t0       ! b_e_2t0       ! t0__4t0_a0
+LSYM(x195)     t0__8a0         ! t0__8t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x196)     t0__8a0         ! t0__3t0       ! b_e_4t0       ! t0__2t0_a0
+LSYM(x197)     t0__8a0         ! t0__3t0       ! b_e_4t0a0     ! t0__2t0_a0
+LSYM(x198)     t0__64a0        ! t0__t0_2a0    ! b_e_t0        ! t0__3t0
+LSYM(x199)     t0__8a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__3t0
+LSYM(x200)     t0__5a0         ! t0__5t0       ! b_e_shift     ! r__r_8t0
+LSYM(x201)     t0__5a0         ! t0__5t0       ! b_e_t0        ! t0__8t0_a0
+LSYM(x202)     t0__5a0         ! t0__5t0       ! b_e_2t0       ! t0__4t0_a0
+LSYM(x203)     t0__5a0         ! t0__5t0       ! b_e_2t0a0     ! t0__4t0_a0
+LSYM(x204)     t0__8a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__3t0
+LSYM(x205)     t0__5a0         ! t0__8t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x206)     t0__64a0        ! t0__t0_4a0    ! b_e_t02a0     ! t0__3t0
+LSYM(x207)     t0__8a0         ! t0__2t0_a0    ! b_e_3t0       ! t0__4t0_a0
+LSYM(x208)     t0__5a0         ! t0__5t0       ! b_e_8t0       ! t0__t0_a0
+LSYM(x209)     t0__5a0         ! t0__5t0       ! b_e_8t0a0     ! t0__t0_a0
+LSYM(x210)     t0__5a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__5t0
+LSYM(x211)     t0__5a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__5t0
+LSYM(x212)     t0__3a0         ! t0__4t0_a0    ! b_e_4t0       ! t0__4t0_a0
+LSYM(x213)     t0__3a0         ! t0__4t0_a0    ! b_e_4t0a0     ! t0__4t0_a0
+LSYM(x214)     t0__9a0         ! t0__t0_4a0    ! b_e_2t04a0    ! t0__8t0_a0
+LSYM(x215)     t0__5a0         ! t0__4t0_a0    ! b_e_5t0       ! t0__2t0_a0
+LSYM(x216)     t0__9a0         ! t0__3t0       ! b_e_shift     ! r__r_8t0
+LSYM(x217)     t0__9a0         ! t0__3t0       ! b_e_t0        ! t0__8t0_a0
+LSYM(x218)     t0__9a0         ! t0__3t0       ! b_e_2t0       ! t0__4t0_a0
+LSYM(x219)     t0__9a0         ! t0__8t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x220)     t0__3a0         ! t0__9t0       ! b_e_4t0       ! t0__2t0_a0
+LSYM(x221)     t0__3a0         ! t0__9t0       ! b_e_4t0a0     ! t0__2t0_a0
+LSYM(x222)     t0__9a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__3t0
+LSYM(x223)     t0__9a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__3t0
+LSYM(x224)     t0__9a0         ! t0__3t0       ! b_e_8t0       ! t0__t0_a0
+LSYM(x225)     t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__5t0
+LSYM(x226)     t0__3a0         ! t0__2t0_a0    ! b_e_t02a0     ! t0__32t0
+LSYM(x227)     t0__9a0         ! t0__5t0       ! b_e_t02a0     ! t0__5t0
+LSYM(x228)     t0__9a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__3t0
+LSYM(x229)     t0__9a0         ! t0__2t0_a0    ! b_e_4t0a0     ! t0__3t0
+LSYM(x230)     t0__9a0         ! t0__5t0       ! b_e_5t0       ! t0__t0_a0
+LSYM(x231)     t0__9a0         ! t0__2t0_a0    ! b_e_3t0       ! t0__4t0_a0
+LSYM(x232)     t0__3a0         ! t0__2t0_a0    ! b_e_8t0       ! t0__4t0_a0
+LSYM(x233)     t0__3a0         ! t0__2t0_a0    ! b_e_8t0a0     ! t0__4t0_a0
+LSYM(x234)     t0__3a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__9t0
+LSYM(x235)     t0__3a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__9t0
+LSYM(x236)     t0__9a0         ! t0__2t0_a0    ! b_e_4t08a0    ! t0__3t0
+LSYM(x237)     t0__16a0        ! t0__5t0       ! b_e_3t0       ! t0__t0ma0
+LSYM(x238)     t0__3a0         ! t0__4t0_a0    ! b_e_2t04a0    ! t0__9t0
+LSYM(x239)     t0__16a0        ! t0__5t0       ! b_e_t0ma0     ! t0__3t0
+LSYM(x240)     t0__9a0         ! t0__t0_a0     ! b_e_8t0       ! t0__3t0
+LSYM(x241)     t0__9a0         ! t0__t0_a0     ! b_e_8t0a0     ! t0__3t0
+LSYM(x242)     t0__5a0         ! t0__3t0       ! b_e_2t0       ! t0__8t0_a0
+LSYM(x243)     t0__9a0         ! t0__9t0       ! b_e_t0        ! t0__3t0
+LSYM(x244)     t0__5a0         ! t0__3t0       ! b_e_4t0       ! t0__4t0_a0
+LSYM(x245)     t0__8a0         ! t0__3t0       ! b_e_5t0       ! t0__2t0_a0
+LSYM(x246)     t0__5a0         ! t0__8t0_a0    ! b_e_2t0       ! t0__3t0
+LSYM(x247)     t0__5a0         ! t0__8t0_a0    ! b_e_2t0a0     ! t0__3t0
+LSYM(x248)     t0__32a0        ! t0__t0ma0     ! b_e_shift     ! r__r_8t0
+LSYM(x249)     t0__32a0        ! t0__t0ma0     ! b_e_t0        ! t0__8t0_a0
+LSYM(x250)     t0__5a0         ! t0__5t0       ! b_e_2t0       ! t0__5t0
+LSYM(x251)     t0__5a0         ! t0__5t0       ! b_e_2t0a0     ! t0__5t0
+LSYM(x252)     t0__64a0        ! t0__t0ma0     ! b_e_shift     ! r__r_4t0
+LSYM(x253)     t0__64a0        ! t0__t0ma0     ! b_e_t0        ! t0__4t0_a0
+LSYM(x254)     t0__128a0       ! t0__t0ma0     ! b_e_shift     ! r__r_2t0
+LSYM(x255)     t0__256a0       ! a1_ne_0_b_l0  ! t0__t0ma0     ! b_n_ret_t0
+/*1040 insts before this.  */
+LSYM(ret_t0)   MILLIRET
+LSYM(e_t0)     r__r_t0
+LSYM(e_shift)  a1_ne_0_b_l2
+       a0__256a0       /* a0 <<= 8 *********** */
+       MILLIRETN
+LSYM(e_t0ma0)  a1_ne_0_b_l0
+       t0__t0ma0
+       MILLIRET
+       r__r_t0
+LSYM(e_t0a0)   a1_ne_0_b_l0
+       t0__t0_a0
+       MILLIRET
+       r__r_t0
+LSYM(e_t02a0)  a1_ne_0_b_l0
+       t0__t0_2a0
+       MILLIRET
+       r__r_t0
+LSYM(e_t04a0)  a1_ne_0_b_l0
+       t0__t0_4a0
+       MILLIRET
+       r__r_t0
+LSYM(e_2t0)    a1_ne_0_b_l1
+       r__r_2t0
+       MILLIRETN
+LSYM(e_2t0a0)  a1_ne_0_b_l0
+       t0__2t0_a0
+       MILLIRET
+       r__r_t0
+LSYM(e2t04a0)  t0__t0_2a0
+       a1_ne_0_b_l1
+       r__r_2t0
+       MILLIRETN
+LSYM(e_3t0)    a1_ne_0_b_l0
+       t0__3t0
+       MILLIRET
+       r__r_t0
+LSYM(e_4t0)    a1_ne_0_b_l1
+       r__r_4t0
+       MILLIRETN
+LSYM(e_4t0a0)  a1_ne_0_b_l0
+       t0__4t0_a0
+       MILLIRET
+       r__r_t0
+LSYM(e4t08a0)  t0__t0_2a0
+       a1_ne_0_b_l1
+       r__r_4t0
+       MILLIRETN
+LSYM(e_5t0)    a1_ne_0_b_l0
+       t0__5t0
+       MILLIRET
+       r__r_t0
+LSYM(e_8t0)    a1_ne_0_b_l1
+       r__r_8t0
+       MILLIRETN
+LSYM(e_8t0a0)  a1_ne_0_b_l0
+       t0__8t0_a0
+       MILLIRET
+       r__r_t0
+
+       .procend
+       .end
+#endif
diff --git a/arch/parisc/lib/milli/milli.h b/arch/parisc/lib/milli/milli.h
new file mode 100644 (file)
index 0000000..19ac79f
--- /dev/null
@@ -0,0 +1,165 @@
+/* 32 and 64-bit millicode, original author Hewlett-Packard
+   adapted for gcc by Paul Bame <bame@debian.org>
+   and Alan Modra <alan@linuxcare.com.au>.
+
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This file is part of GCC and is released under the terms of
+   of the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+   See the file COPYING in the top-level GCC source directory for a copy
+   of the license.  */
+
+#ifndef _PA_MILLI_H_
+#define _PA_MILLI_H_
+
+#define L_dyncall
+#define L_divI
+#define L_divU
+#define L_remI
+#define L_remU
+#define L_div_const
+#define L_mulI
+
+#ifdef CONFIG_64BIT
+        .level  2.0w
+#endif
+
+/* Hardware General Registers.  */
+r0:    .reg    %r0
+r1:    .reg    %r1
+r2:    .reg    %r2
+r3:    .reg    %r3
+r4:    .reg    %r4
+r5:    .reg    %r5
+r6:    .reg    %r6
+r7:    .reg    %r7
+r8:    .reg    %r8
+r9:    .reg    %r9
+r10:   .reg    %r10
+r11:   .reg    %r11
+r12:   .reg    %r12
+r13:   .reg    %r13
+r14:   .reg    %r14
+r15:   .reg    %r15
+r16:   .reg    %r16
+r17:   .reg    %r17
+r18:   .reg    %r18
+r19:   .reg    %r19
+r20:   .reg    %r20
+r21:   .reg    %r21
+r22:   .reg    %r22
+r23:   .reg    %r23
+r24:   .reg    %r24
+r25:   .reg    %r25
+r26:   .reg    %r26
+r27:   .reg    %r27
+r28:   .reg    %r28
+r29:   .reg    %r29
+r30:   .reg    %r30
+r31:   .reg    %r31
+
+/* Hardware Space Registers.  */
+sr0:   .reg    %sr0
+sr1:   .reg    %sr1
+sr2:   .reg    %sr2
+sr3:   .reg    %sr3
+sr4:   .reg    %sr4
+sr5:   .reg    %sr5
+sr6:   .reg    %sr6
+sr7:   .reg    %sr7
+
+/* Hardware Floating Point Registers.  */
+fr0:   .reg    %fr0
+fr1:   .reg    %fr1
+fr2:   .reg    %fr2
+fr3:   .reg    %fr3
+fr4:   .reg    %fr4
+fr5:   .reg    %fr5
+fr6:   .reg    %fr6
+fr7:   .reg    %fr7
+fr8:   .reg    %fr8
+fr9:   .reg    %fr9
+fr10:  .reg    %fr10
+fr11:  .reg    %fr11
+fr12:  .reg    %fr12
+fr13:  .reg    %fr13
+fr14:  .reg    %fr14
+fr15:  .reg    %fr15
+
+/* Hardware Control Registers.  */
+cr11:  .reg    %cr11
+sar:   .reg    %cr11   /* Shift Amount Register */
+
+/* Software Architecture General Registers.  */
+rp:    .reg    r2      /* return pointer */
+#ifdef CONFIG_64BIT
+mrp:   .reg    r2      /* millicode return pointer */
+#else
+mrp:   .reg    r31     /* millicode return pointer */
+#endif
+ret0:  .reg    r28     /* return value */
+ret1:  .reg    r29     /* return value (high part of double) */
+sp:    .reg    r30     /* stack pointer */
+dp:    .reg    r27     /* data pointer */
+arg0:  .reg    r26     /* argument */
+arg1:  .reg    r25     /* argument or high part of double argument */
+arg2:  .reg    r24     /* argument */
+arg3:  .reg    r23     /* argument or high part of double argument */
+
+/* Software Architecture Space Registers.  */
+/*             sr0     ; return link from BLE */
+sret:  .reg    sr1     /* return value */
+sarg:  .reg    sr1     /* argument */
+/*             sr4     ; PC SPACE tracker */
+/*             sr5     ; process private data */
+
+/* Frame Offsets (millicode convention!)  Used when calling other
+   millicode routines.  Stack unwinding is dependent upon these
+   definitions.  */
+r31_slot:      .equ    -20     /* "current RP" slot */
+sr0_slot:      .equ    -16     /* "static link" slot */
+#if defined(CONFIG_64BIT)
+mrp_slot:       .equ    -16    /* "current RP" slot */
+psp_slot:       .equ    -8     /* "previous SP" slot */
+#else
+mrp_slot:      .equ    -20     /* "current RP" slot (replacing "r31_slot") */
+#endif
+
+
+#define DEFINE(name,value)name:        .EQU    value
+#define RDEFINE(name,value)name:       .REG    value
+#ifdef milliext
+#define MILLI_BE(lbl)   BE    lbl(sr7,r0)
+#define MILLI_BEN(lbl)  BE,n  lbl(sr7,r0)
+#define MILLI_BLE(lbl) BLE   lbl(sr7,r0)
+#define MILLI_BLEN(lbl)        BLE,n lbl(sr7,r0)
+#define MILLIRETN      BE,n  0(sr0,mrp)
+#define MILLIRET       BE    0(sr0,mrp)
+#define MILLI_RETN     BE,n  0(sr0,mrp)
+#define MILLI_RET      BE    0(sr0,mrp)
+#else
+#define MILLI_BE(lbl)  B     lbl
+#define MILLI_BEN(lbl)  B,n   lbl
+#define MILLI_BLE(lbl) BL    lbl,mrp
+#define MILLI_BLEN(lbl)        BL,n  lbl,mrp
+#define MILLIRETN      BV,n  0(mrp)
+#define MILLIRET       BV    0(mrp)
+#define MILLI_RETN     BV,n  0(mrp)
+#define MILLI_RET      BV    0(mrp)
+#endif
+
+#define CAT(a,b)       a##b
+
+#define SUBSPA_MILLI    .section .text
+#define SUBSPA_MILLI_DIV .section .text.div,"ax",@progbits! .align 16
+#define SUBSPA_MILLI_MUL .section .text.mul,"ax",@progbits! .align 16
+#define ATTR_MILLI
+#define SUBSPA_DATA     .section .data
+#define ATTR_DATA
+#define GLOBAL          $global$
+#define GSYM(sym)       !sym:
+#define LSYM(sym)       !CAT(.L,sym:)
+#define LREF(sym)       CAT(.L,sym)
+
+#endif /*_PA_MILLI_H_*/
diff --git a/arch/parisc/lib/milli/mulI.S b/arch/parisc/lib/milli/mulI.S
new file mode 100644 (file)
index 0000000..4c7e0c3
--- /dev/null
@@ -0,0 +1,474 @@
+/* 32 and 64-bit millicode, original author Hewlett-Packard
+   adapted for gcc by Paul Bame <bame@debian.org>
+   and Alan Modra <alan@linuxcare.com.au>.
+
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This file is part of GCC and is released under the terms of
+   of the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+   See the file COPYING in the top-level GCC source directory for a copy
+   of the license.  */
+
+#include "milli.h"
+
+#ifdef L_mulI
+/* VERSION "@(#)$$mulI $ Revision: 12.4 $ $ Date: 94/03/17 17:18:51 $" */
+/******************************************************************************
+This routine is used on PA2.0 processors when gcc -mno-fpregs is used
+
+ROUTINE:       $$mulI
+
+
+DESCRIPTION:   
+
+       $$mulI multiplies two single word integers, giving a single 
+       word result.  
+
+
+INPUT REGISTERS:
+
+       arg0 = Operand 1
+       arg1 = Operand 2
+       r31  == return pc
+       sr0  == return space when called externally 
+
+
+OUTPUT REGISTERS:
+
+       arg0 = undefined
+       arg1 = undefined
+       ret1 = result 
+
+OTHER REGISTERS AFFECTED:
+
+       r1   = undefined
+
+SIDE EFFECTS:
+
+       Causes a trap under the following conditions:  NONE
+       Changes memory at the following places:  NONE
+
+PERMISSIBLE CONTEXT:
+
+       Unwindable
+       Does not create a stack frame
+       Is usable for internal or external microcode
+
+DISCUSSION:
+
+       Calls other millicode routines via mrp:  NONE
+       Calls other millicode routines:  NONE
+
+***************************************************************************/
+
+
+#define        a0      %arg0
+#define        a1      %arg1
+#define        t0      %r1
+#define        r       %ret1
+
+#define        a0__128a0       zdep    a0,24,25,a0
+#define        a0__256a0       zdep    a0,23,24,a0
+#define        a1_ne_0_b_l0    comb,<> a1,0,LREF(l0)
+#define        a1_ne_0_b_l1    comb,<> a1,0,LREF(l1)
+#define        a1_ne_0_b_l2    comb,<> a1,0,LREF(l2)
+#define        b_n_ret_t0      b,n     LREF(ret_t0)
+#define        b_e_shift       b       LREF(e_shift)
+#define        b_e_t0ma0       b       LREF(e_t0ma0)
+#define        b_e_t0          b       LREF(e_t0)
+#define        b_e_t0a0        b       LREF(e_t0a0)
+#define        b_e_t02a0       b       LREF(e_t02a0)
+#define        b_e_t04a0       b       LREF(e_t04a0)
+#define        b_e_2t0         b       LREF(e_2t0)
+#define        b_e_2t0a0       b       LREF(e_2t0a0)
+#define        b_e_2t04a0      b       LREF(e2t04a0)
+#define        b_e_3t0         b       LREF(e_3t0)
+#define        b_e_4t0         b       LREF(e_4t0)
+#define        b_e_4t0a0       b       LREF(e_4t0a0)
+#define        b_e_4t08a0      b       LREF(e4t08a0)
+#define        b_e_5t0         b       LREF(e_5t0)
+#define        b_e_8t0         b       LREF(e_8t0)
+#define        b_e_8t0a0       b       LREF(e_8t0a0)
+#define        r__r_a0         add     r,a0,r
+#define        r__r_2a0        sh1add  a0,r,r
+#define        r__r_4a0        sh2add  a0,r,r
+#define        r__r_8a0        sh3add  a0,r,r
+#define        r__r_t0         add     r,t0,r
+#define        r__r_2t0        sh1add  t0,r,r
+#define        r__r_4t0        sh2add  t0,r,r
+#define        r__r_8t0        sh3add  t0,r,r
+#define        t0__3a0         sh1add  a0,a0,t0
+#define        t0__4a0         sh2add  a0,0,t0
+#define        t0__5a0         sh2add  a0,a0,t0
+#define        t0__8a0         sh3add  a0,0,t0
+#define        t0__9a0         sh3add  a0,a0,t0
+#define        t0__16a0        zdep    a0,27,28,t0
+#define        t0__32a0        zdep    a0,26,27,t0
+#define        t0__64a0        zdep    a0,25,26,t0
+#define        t0__128a0       zdep    a0,24,25,t0
+#define        t0__t0ma0       sub     t0,a0,t0
+#define        t0__t0_a0       add     t0,a0,t0
+#define        t0__t0_2a0      sh1add  a0,t0,t0
+#define        t0__t0_4a0      sh2add  a0,t0,t0
+#define        t0__t0_8a0      sh3add  a0,t0,t0
+#define        t0__2t0_a0      sh1add  t0,a0,t0
+#define        t0__3t0         sh1add  t0,t0,t0
+#define        t0__4t0         sh2add  t0,0,t0
+#define        t0__4t0_a0      sh2add  t0,a0,t0
+#define        t0__5t0         sh2add  t0,t0,t0
+#define        t0__8t0         sh3add  t0,0,t0
+#define        t0__8t0_a0      sh3add  t0,a0,t0
+#define        t0__9t0         sh3add  t0,t0,t0
+#define        t0__16t0        zdep    t0,27,28,t0
+#define        t0__32t0        zdep    t0,26,27,t0
+#define        t0__256a0       zdep    a0,23,24,t0
+
+
+       SUBSPA_MILLI
+       ATTR_MILLI
+       .align 16
+       .proc
+       .callinfo millicode
+       .export $$mulI,millicode
+GSYM($$mulI)   
+       combt,<<=       a1,a0,LREF(l4)  /* swap args if unsigned a1>a0 */
+       copy            0,r             /* zero out the result */
+       xor             a0,a1,a0        /* swap a0 & a1 using the */
+       xor             a0,a1,a1        /*  old xor trick */
+       xor             a0,a1,a0
+LSYM(l4)
+       combt,<=        0,a0,LREF(l3)           /* if a0>=0 then proceed like unsigned */
+       zdep            a1,30,8,t0      /* t0 = (a1&0xff)<<1 ********* */
+       sub,>           0,a1,t0         /* otherwise negate both and */
+       combt,<=,n      a0,t0,LREF(l2)  /*  swap back if |a0|<|a1| */
+       sub             0,a0,a1
+       movb,tr,n       t0,a0,LREF(l2)  /* 10th inst.  */
+
+LSYM(l0)       r__r_t0                         /* add in this partial product */
+LSYM(l1)       a0__256a0                       /* a0 <<= 8 ****************** */
+LSYM(l2)       zdep            a1,30,8,t0      /* t0 = (a1&0xff)<<1 ********* */
+LSYM(l3)       blr             t0,0            /* case on these 8 bits ****** */
+               extru           a1,23,24,a1     /* a1 >>= 8 ****************** */
+
+/*16 insts before this.  */
+/*                       a0 <<= 8 ************************** */
+LSYM(x0)       a1_ne_0_b_l2    ! a0__256a0     ! MILLIRETN     ! nop
+LSYM(x1)       a1_ne_0_b_l1    ! r__r_a0       ! MILLIRETN     ! nop
+LSYM(x2)       a1_ne_0_b_l1    ! r__r_2a0      ! MILLIRETN     ! nop
+LSYM(x3)       a1_ne_0_b_l0    ! t0__3a0       ! MILLIRET      ! r__r_t0
+LSYM(x4)       a1_ne_0_b_l1    ! r__r_4a0      ! MILLIRETN     ! nop
+LSYM(x5)       a1_ne_0_b_l0    ! t0__5a0       ! MILLIRET      ! r__r_t0
+LSYM(x6)       t0__3a0         ! a1_ne_0_b_l1  ! r__r_2t0      ! MILLIRETN
+LSYM(x7)       t0__3a0         ! a1_ne_0_b_l0  ! r__r_4a0      ! b_n_ret_t0
+LSYM(x8)       a1_ne_0_b_l1    ! r__r_8a0      ! MILLIRETN     ! nop
+LSYM(x9)       a1_ne_0_b_l0    ! t0__9a0       ! MILLIRET      ! r__r_t0
+LSYM(x10)      t0__5a0         ! a1_ne_0_b_l1  ! r__r_2t0      ! MILLIRETN
+LSYM(x11)      t0__3a0         ! a1_ne_0_b_l0  ! r__r_8a0      ! b_n_ret_t0
+LSYM(x12)      t0__3a0         ! a1_ne_0_b_l1  ! r__r_4t0      ! MILLIRETN
+LSYM(x13)      t0__5a0         ! a1_ne_0_b_l0  ! r__r_8a0      ! b_n_ret_t0
+LSYM(x14)      t0__3a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x15)      t0__5a0         ! a1_ne_0_b_l0  ! t0__3t0       ! b_n_ret_t0
+LSYM(x16)      t0__16a0        ! a1_ne_0_b_l1  ! r__r_t0       ! MILLIRETN
+LSYM(x17)      t0__9a0         ! a1_ne_0_b_l0  ! t0__t0_8a0    ! b_n_ret_t0
+LSYM(x18)      t0__9a0         ! a1_ne_0_b_l1  ! r__r_2t0      ! MILLIRETN
+LSYM(x19)      t0__9a0         ! a1_ne_0_b_l0  ! t0__2t0_a0    ! b_n_ret_t0
+LSYM(x20)      t0__5a0         ! a1_ne_0_b_l1  ! r__r_4t0      ! MILLIRETN
+LSYM(x21)      t0__5a0         ! a1_ne_0_b_l0  ! t0__4t0_a0    ! b_n_ret_t0
+LSYM(x22)      t0__5a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x23)      t0__5a0         ! t0__2t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x24)      t0__3a0         ! a1_ne_0_b_l1  ! r__r_8t0      ! MILLIRETN
+LSYM(x25)      t0__5a0         ! a1_ne_0_b_l0  ! t0__5t0       ! b_n_ret_t0
+LSYM(x26)      t0__3a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x27)      t0__3a0         ! a1_ne_0_b_l0  ! t0__9t0       ! b_n_ret_t0
+LSYM(x28)      t0__3a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x29)      t0__3a0         ! t0__2t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x30)      t0__5a0         ! t0__3t0       ! b_e_shift     ! r__r_2t0
+LSYM(x31)      t0__32a0        ! a1_ne_0_b_l0  ! t0__t0ma0     ! b_n_ret_t0
+LSYM(x32)      t0__32a0        ! a1_ne_0_b_l1  ! r__r_t0       ! MILLIRETN
+LSYM(x33)      t0__8a0         ! a1_ne_0_b_l0  ! t0__4t0_a0    ! b_n_ret_t0
+LSYM(x34)      t0__16a0        ! t0__t0_a0     ! b_e_shift     ! r__r_2t0
+LSYM(x35)      t0__9a0         ! t0__3t0       ! b_e_t0        ! t0__t0_8a0
+LSYM(x36)      t0__9a0         ! a1_ne_0_b_l1  ! r__r_4t0      ! MILLIRETN
+LSYM(x37)      t0__9a0         ! a1_ne_0_b_l0  ! t0__4t0_a0    ! b_n_ret_t0
+LSYM(x38)      t0__9a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x39)      t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x40)      t0__5a0         ! a1_ne_0_b_l1  ! r__r_8t0      ! MILLIRETN
+LSYM(x41)      t0__5a0         ! a1_ne_0_b_l0  ! t0__8t0_a0    ! b_n_ret_t0
+LSYM(x42)      t0__5a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x43)      t0__5a0         ! t0__4t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x44)      t0__5a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x45)      t0__9a0         ! a1_ne_0_b_l0  ! t0__5t0       ! b_n_ret_t0
+LSYM(x46)      t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__t0_a0
+LSYM(x47)      t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__t0_2a0
+LSYM(x48)      t0__3a0         ! a1_ne_0_b_l0  ! t0__16t0      ! b_n_ret_t0
+LSYM(x49)      t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__t0_4a0
+LSYM(x50)      t0__5a0         ! t0__5t0       ! b_e_shift     ! r__r_2t0
+LSYM(x51)      t0__9a0         ! t0__t0_8a0    ! b_e_t0        ! t0__3t0
+LSYM(x52)      t0__3a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x53)      t0__3a0         ! t0__4t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x54)      t0__9a0         ! t0__3t0       ! b_e_shift     ! r__r_2t0
+LSYM(x55)      t0__9a0         ! t0__3t0       ! b_e_t0        ! t0__2t0_a0
+LSYM(x56)      t0__3a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x57)      t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x58)      t0__3a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__4t0_a0
+LSYM(x59)      t0__9a0         ! t0__2t0_a0    ! b_e_t02a0     ! t0__3t0
+LSYM(x60)      t0__5a0         ! t0__3t0       ! b_e_shift     ! r__r_4t0
+LSYM(x61)      t0__5a0         ! t0__3t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x62)      t0__32a0        ! t0__t0ma0     ! b_e_shift     ! r__r_2t0
+LSYM(x63)      t0__64a0        ! a1_ne_0_b_l0  ! t0__t0ma0     ! b_n_ret_t0
+LSYM(x64)      t0__64a0        ! a1_ne_0_b_l1  ! r__r_t0       ! MILLIRETN
+LSYM(x65)      t0__8a0         ! a1_ne_0_b_l0  ! t0__8t0_a0    ! b_n_ret_t0
+LSYM(x66)      t0__32a0        ! t0__t0_a0     ! b_e_shift     ! r__r_2t0
+LSYM(x67)      t0__8a0         ! t0__4t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x68)      t0__8a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x69)      t0__8a0         ! t0__2t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x70)      t0__64a0        ! t0__t0_4a0    ! b_e_t0        ! t0__t0_2a0
+LSYM(x71)      t0__9a0         ! t0__8t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x72)      t0__9a0         ! a1_ne_0_b_l1  ! r__r_8t0      ! MILLIRETN
+LSYM(x73)      t0__9a0         ! t0__8t0_a0    ! b_e_shift     ! r__r_t0
+LSYM(x74)      t0__9a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x75)      t0__9a0         ! t0__4t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x76)      t0__9a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x77)      t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x78)      t0__9a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x79)      t0__16a0        ! t0__5t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x80)      t0__16a0        ! t0__5t0       ! b_e_shift     ! r__r_t0
+LSYM(x81)      t0__9a0         ! t0__9t0       ! b_e_shift     ! r__r_t0
+LSYM(x82)      t0__5a0         ! t0__8t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x83)      t0__5a0         ! t0__8t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x84)      t0__5a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x85)      t0__8a0         ! t0__2t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x86)      t0__5a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x87)      t0__9a0         ! t0__9t0       ! b_e_t02a0     ! t0__t0_4a0
+LSYM(x88)      t0__5a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x89)      t0__5a0         ! t0__2t0_a0    ! b_e_t0        ! t0__8t0_a0
+LSYM(x90)      t0__9a0         ! t0__5t0       ! b_e_shift     ! r__r_2t0
+LSYM(x91)      t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__2t0_a0
+LSYM(x92)      t0__5a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__2t0_a0
+LSYM(x93)      t0__32a0        ! t0__t0ma0     ! b_e_t0        ! t0__3t0
+LSYM(x94)      t0__9a0         ! t0__5t0       ! b_e_2t0       ! t0__t0_2a0
+LSYM(x95)      t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x96)      t0__8a0         ! t0__3t0       ! b_e_shift     ! r__r_4t0
+LSYM(x97)      t0__8a0         ! t0__3t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x98)      t0__32a0        ! t0__3t0       ! b_e_t0        ! t0__t0_2a0
+LSYM(x99)      t0__8a0         ! t0__4t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x100)     t0__5a0         ! t0__5t0       ! b_e_shift     ! r__r_4t0
+LSYM(x101)     t0__5a0         ! t0__5t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x102)     t0__32a0        ! t0__t0_2a0    ! b_e_t0        ! t0__3t0
+LSYM(x103)     t0__5a0         ! t0__5t0       ! b_e_t02a0     ! t0__4t0_a0
+LSYM(x104)     t0__3a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x105)     t0__5a0         ! t0__4t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x106)     t0__3a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__4t0_a0
+LSYM(x107)     t0__9a0         ! t0__t0_4a0    ! b_e_t02a0     ! t0__8t0_a0
+LSYM(x108)     t0__9a0         ! t0__3t0       ! b_e_shift     ! r__r_4t0
+LSYM(x109)     t0__9a0         ! t0__3t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x110)     t0__9a0         ! t0__3t0       ! b_e_2t0       ! t0__2t0_a0
+LSYM(x111)     t0__9a0         ! t0__4t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x112)     t0__3a0         ! t0__2t0_a0    ! b_e_t0        ! t0__16t0
+LSYM(x113)     t0__9a0         ! t0__4t0_a0    ! b_e_t02a0     ! t0__3t0
+LSYM(x114)     t0__9a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__3t0
+LSYM(x115)     t0__9a0         ! t0__2t0_a0    ! b_e_2t0a0     ! t0__3t0
+LSYM(x116)     t0__3a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__4t0_a0
+LSYM(x117)     t0__3a0         ! t0__4t0_a0    ! b_e_t0        ! t0__9t0
+LSYM(x118)     t0__3a0         ! t0__4t0_a0    ! b_e_t0a0      ! t0__9t0
+LSYM(x119)     t0__3a0         ! t0__4t0_a0    ! b_e_t02a0     ! t0__9t0
+LSYM(x120)     t0__5a0         ! t0__3t0       ! b_e_shift     ! r__r_8t0
+LSYM(x121)     t0__5a0         ! t0__3t0       ! b_e_t0        ! t0__8t0_a0
+LSYM(x122)     t0__5a0         ! t0__3t0       ! b_e_2t0       ! t0__4t0_a0
+LSYM(x123)     t0__5a0         ! t0__8t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x124)     t0__32a0        ! t0__t0ma0     ! b_e_shift     ! r__r_4t0
+LSYM(x125)     t0__5a0         ! t0__5t0       ! b_e_t0        ! t0__5t0
+LSYM(x126)     t0__64a0        ! t0__t0ma0     ! b_e_shift     ! r__r_2t0
+LSYM(x127)     t0__128a0       ! a1_ne_0_b_l0  ! t0__t0ma0     ! b_n_ret_t0
+LSYM(x128)     t0__128a0       ! a1_ne_0_b_l1  ! r__r_t0       ! MILLIRETN
+LSYM(x129)     t0__128a0       ! a1_ne_0_b_l0  ! t0__t0_a0     ! b_n_ret_t0
+LSYM(x130)     t0__64a0        ! t0__t0_a0     ! b_e_shift     ! r__r_2t0
+LSYM(x131)     t0__8a0         ! t0__8t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x132)     t0__8a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x133)     t0__8a0         ! t0__4t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x134)     t0__8a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x135)     t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__3t0
+LSYM(x136)     t0__8a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x137)     t0__8a0         ! t0__2t0_a0    ! b_e_t0        ! t0__8t0_a0
+LSYM(x138)     t0__8a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__4t0_a0
+LSYM(x139)     t0__8a0         ! t0__2t0_a0    ! b_e_2t0a0     ! t0__4t0_a0
+LSYM(x140)     t0__3a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__5t0
+LSYM(x141)     t0__8a0         ! t0__2t0_a0    ! b_e_4t0a0     ! t0__2t0_a0
+LSYM(x142)     t0__9a0         ! t0__8t0       ! b_e_2t0       ! t0__t0ma0
+LSYM(x143)     t0__16a0        ! t0__9t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x144)     t0__9a0         ! t0__8t0       ! b_e_shift     ! r__r_2t0
+LSYM(x145)     t0__9a0         ! t0__8t0       ! b_e_t0        ! t0__2t0_a0
+LSYM(x146)     t0__9a0         ! t0__8t0_a0    ! b_e_shift     ! r__r_2t0
+LSYM(x147)     t0__9a0         ! t0__8t0_a0    ! b_e_t0        ! t0__2t0_a0
+LSYM(x148)     t0__9a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x149)     t0__9a0         ! t0__4t0_a0    ! b_e_t0        ! t0__4t0_a0
+LSYM(x150)     t0__9a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x151)     t0__9a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__2t0_a0
+LSYM(x152)     t0__9a0         ! t0__2t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x153)     t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__8t0_a0
+LSYM(x154)     t0__9a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__4t0_a0
+LSYM(x155)     t0__32a0        ! t0__t0ma0     ! b_e_t0        ! t0__5t0
+LSYM(x156)     t0__9a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__2t0_a0
+LSYM(x157)     t0__32a0        ! t0__t0ma0     ! b_e_t02a0     ! t0__5t0
+LSYM(x158)     t0__16a0        ! t0__5t0       ! b_e_2t0       ! t0__t0ma0
+LSYM(x159)     t0__32a0        ! t0__5t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x160)     t0__5a0         ! t0__4t0       ! b_e_shift     ! r__r_8t0
+LSYM(x161)     t0__8a0         ! t0__5t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x162)     t0__9a0         ! t0__9t0       ! b_e_shift     ! r__r_2t0
+LSYM(x163)     t0__9a0         ! t0__9t0       ! b_e_t0        ! t0__2t0_a0
+LSYM(x164)     t0__5a0         ! t0__8t0_a0    ! b_e_shift     ! r__r_4t0
+LSYM(x165)     t0__8a0         ! t0__4t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x166)     t0__5a0         ! t0__8t0_a0    ! b_e_2t0       ! t0__2t0_a0
+LSYM(x167)     t0__5a0         ! t0__8t0_a0    ! b_e_2t0a0     ! t0__2t0_a0
+LSYM(x168)     t0__5a0         ! t0__4t0_a0    ! b_e_shift     ! r__r_8t0
+LSYM(x169)     t0__5a0         ! t0__4t0_a0    ! b_e_t0        ! t0__8t0_a0
+LSYM(x170)     t0__32a0        ! t0__t0_2a0    ! b_e_t0        ! t0__5t0
+LSYM(x171)     t0__9a0         ! t0__2t0_a0    ! b_e_t0        ! t0__9t0
+LSYM(x172)     t0__5a0         ! t0__4t0_a0    ! b_e_4t0       ! t0__2t0_a0
+LSYM(x173)     t0__9a0         ! t0__2t0_a0    ! b_e_t02a0     ! t0__9t0
+LSYM(x174)     t0__32a0        ! t0__t0_2a0    ! b_e_t04a0     ! t0__5t0
+LSYM(x175)     t0__8a0         ! t0__2t0_a0    ! b_e_5t0       ! t0__2t0_a0
+LSYM(x176)     t0__5a0         ! t0__4t0_a0    ! b_e_8t0       ! t0__t0_a0
+LSYM(x177)     t0__5a0         ! t0__4t0_a0    ! b_e_8t0a0     ! t0__t0_a0
+LSYM(x178)     t0__5a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__8t0_a0
+LSYM(x179)     t0__5a0         ! t0__2t0_a0    ! b_e_2t0a0     ! t0__8t0_a0
+LSYM(x180)     t0__9a0         ! t0__5t0       ! b_e_shift     ! r__r_4t0
+LSYM(x181)     t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__4t0_a0
+LSYM(x182)     t0__9a0         ! t0__5t0       ! b_e_2t0       ! t0__2t0_a0
+LSYM(x183)     t0__9a0         ! t0__5t0       ! b_e_2t0a0     ! t0__2t0_a0
+LSYM(x184)     t0__5a0         ! t0__9t0       ! b_e_4t0       ! t0__t0_a0
+LSYM(x185)     t0__9a0         ! t0__4t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x186)     t0__32a0        ! t0__t0ma0     ! b_e_2t0       ! t0__3t0
+LSYM(x187)     t0__9a0         ! t0__4t0_a0    ! b_e_t02a0     ! t0__5t0
+LSYM(x188)     t0__9a0         ! t0__5t0       ! b_e_4t0       ! t0__t0_2a0
+LSYM(x189)     t0__5a0         ! t0__4t0_a0    ! b_e_t0        ! t0__9t0
+LSYM(x190)     t0__9a0         ! t0__2t0_a0    ! b_e_2t0       ! t0__5t0
+LSYM(x191)     t0__64a0        ! t0__3t0       ! b_e_t0        ! t0__t0ma0
+LSYM(x192)     t0__8a0         ! t0__3t0       ! b_e_shift     ! r__r_8t0
+LSYM(x193)     t0__8a0         ! t0__3t0       ! b_e_t0        ! t0__8t0_a0
+LSYM(x194)     t0__8a0         ! t0__3t0       ! b_e_2t0       ! t0__4t0_a0
+LSYM(x195)     t0__8a0         ! t0__8t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x196)     t0__8a0         ! t0__3t0       ! b_e_4t0       ! t0__2t0_a0
+LSYM(x197)     t0__8a0         ! t0__3t0       ! b_e_4t0a0     ! t0__2t0_a0
+LSYM(x198)     t0__64a0        ! t0__t0_2a0    ! b_e_t0        ! t0__3t0
+LSYM(x199)     t0__8a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__3t0
+LSYM(x200)     t0__5a0         ! t0__5t0       ! b_e_shift     ! r__r_8t0
+LSYM(x201)     t0__5a0         ! t0__5t0       ! b_e_t0        ! t0__8t0_a0
+LSYM(x202)     t0__5a0         ! t0__5t0       ! b_e_2t0       ! t0__4t0_a0
+LSYM(x203)     t0__5a0         ! t0__5t0       ! b_e_2t0a0     ! t0__4t0_a0
+LSYM(x204)     t0__8a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__3t0
+LSYM(x205)     t0__5a0         ! t0__8t0_a0    ! b_e_t0        ! t0__5t0
+LSYM(x206)     t0__64a0        ! t0__t0_4a0    ! b_e_t02a0     ! t0__3t0
+LSYM(x207)     t0__8a0         ! t0__2t0_a0    ! b_e_3t0       ! t0__4t0_a0
+LSYM(x208)     t0__5a0         ! t0__5t0       ! b_e_8t0       ! t0__t0_a0
+LSYM(x209)     t0__5a0         ! t0__5t0       ! b_e_8t0a0     ! t0__t0_a0
+LSYM(x210)     t0__5a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__5t0
+LSYM(x211)     t0__5a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__5t0
+LSYM(x212)     t0__3a0         ! t0__4t0_a0    ! b_e_4t0       ! t0__4t0_a0
+LSYM(x213)     t0__3a0         ! t0__4t0_a0    ! b_e_4t0a0     ! t0__4t0_a0
+LSYM(x214)     t0__9a0         ! t0__t0_4a0    ! b_e_2t04a0    ! t0__8t0_a0
+LSYM(x215)     t0__5a0         ! t0__4t0_a0    ! b_e_5t0       ! t0__2t0_a0
+LSYM(x216)     t0__9a0         ! t0__3t0       ! b_e_shift     ! r__r_8t0
+LSYM(x217)     t0__9a0         ! t0__3t0       ! b_e_t0        ! t0__8t0_a0
+LSYM(x218)     t0__9a0         ! t0__3t0       ! b_e_2t0       ! t0__4t0_a0
+LSYM(x219)     t0__9a0         ! t0__8t0_a0    ! b_e_t0        ! t0__3t0
+LSYM(x220)     t0__3a0         ! t0__9t0       ! b_e_4t0       ! t0__2t0_a0
+LSYM(x221)     t0__3a0         ! t0__9t0       ! b_e_4t0a0     ! t0__2t0_a0
+LSYM(x222)     t0__9a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__3t0
+LSYM(x223)     t0__9a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__3t0
+LSYM(x224)     t0__9a0         ! t0__3t0       ! b_e_8t0       ! t0__t0_a0
+LSYM(x225)     t0__9a0         ! t0__5t0       ! b_e_t0        ! t0__5t0
+LSYM(x226)     t0__3a0         ! t0__2t0_a0    ! b_e_t02a0     ! t0__32t0
+LSYM(x227)     t0__9a0         ! t0__5t0       ! b_e_t02a0     ! t0__5t0
+LSYM(x228)     t0__9a0         ! t0__2t0_a0    ! b_e_4t0       ! t0__3t0
+LSYM(x229)     t0__9a0         ! t0__2t0_a0    ! b_e_4t0a0     ! t0__3t0
+LSYM(x230)     t0__9a0         ! t0__5t0       ! b_e_5t0       ! t0__t0_a0
+LSYM(x231)     t0__9a0         ! t0__2t0_a0    ! b_e_3t0       ! t0__4t0_a0
+LSYM(x232)     t0__3a0         ! t0__2t0_a0    ! b_e_8t0       ! t0__4t0_a0
+LSYM(x233)     t0__3a0         ! t0__2t0_a0    ! b_e_8t0a0     ! t0__4t0_a0
+LSYM(x234)     t0__3a0         ! t0__4t0_a0    ! b_e_2t0       ! t0__9t0
+LSYM(x235)     t0__3a0         ! t0__4t0_a0    ! b_e_2t0a0     ! t0__9t0
+LSYM(x236)     t0__9a0         ! t0__2t0_a0    ! b_e_4t08a0    ! t0__3t0
+LSYM(x237)     t0__16a0        ! t0__5t0       ! b_e_3t0       ! t0__t0ma0
+LSYM(x238)     t0__3a0         ! t0__4t0_a0    ! b_e_2t04a0    ! t0__9t0
+LSYM(x239)     t0__16a0        ! t0__5t0       ! b_e_t0ma0     ! t0__3t0
+LSYM(x240)     t0__9a0         ! t0__t0_a0     ! b_e_8t0       ! t0__3t0
+LSYM(x241)     t0__9a0         ! t0__t0_a0     ! b_e_8t0a0     ! t0__3t0
+LSYM(x242)     t0__5a0         ! t0__3t0       ! b_e_2t0       ! t0__8t0_a0
+LSYM(x243)     t0__9a0         ! t0__9t0       ! b_e_t0        ! t0__3t0
+LSYM(x244)     t0__5a0         ! t0__3t0       ! b_e_4t0       ! t0__4t0_a0
+LSYM(x245)     t0__8a0         ! t0__3t0       ! b_e_5t0       ! t0__2t0_a0
+LSYM(x246)     t0__5a0         ! t0__8t0_a0    ! b_e_2t0       ! t0__3t0
+LSYM(x247)     t0__5a0         ! t0__8t0_a0    ! b_e_2t0a0     ! t0__3t0
+LSYM(x248)     t0__32a0        ! t0__t0ma0     ! b_e_shift     ! r__r_8t0
+LSYM(x249)     t0__32a0        ! t0__t0ma0     ! b_e_t0        ! t0__8t0_a0
+LSYM(x250)     t0__5a0         ! t0__5t0       ! b_e_2t0       ! t0__5t0
+LSYM(x251)     t0__5a0         ! t0__5t0       ! b_e_2t0a0     ! t0__5t0
+LSYM(x252)     t0__64a0        ! t0__t0ma0     ! b_e_shift     ! r__r_4t0
+LSYM(x253)     t0__64a0        ! t0__t0ma0     ! b_e_t0        ! t0__4t0_a0
+LSYM(x254)     t0__128a0       ! t0__t0ma0     ! b_e_shift     ! r__r_2t0
+LSYM(x255)     t0__256a0       ! a1_ne_0_b_l0  ! t0__t0ma0     ! b_n_ret_t0
+/*1040 insts before this.  */
+LSYM(ret_t0)   MILLIRET
+LSYM(e_t0)     r__r_t0
+LSYM(e_shift)  a1_ne_0_b_l2
+       a0__256a0       /* a0 <<= 8 *********** */
+       MILLIRETN
+LSYM(e_t0ma0)  a1_ne_0_b_l0
+       t0__t0ma0
+       MILLIRET
+       r__r_t0
+LSYM(e_t0a0)   a1_ne_0_b_l0
+       t0__t0_a0
+       MILLIRET
+       r__r_t0
+LSYM(e_t02a0)  a1_ne_0_b_l0
+       t0__t0_2a0
+       MILLIRET
+       r__r_t0
+LSYM(e_t04a0)  a1_ne_0_b_l0
+       t0__t0_4a0
+       MILLIRET
+       r__r_t0
+LSYM(e_2t0)    a1_ne_0_b_l1
+       r__r_2t0
+       MILLIRETN
+LSYM(e_2t0a0)  a1_ne_0_b_l0
+       t0__2t0_a0
+       MILLIRET
+       r__r_t0
+LSYM(e2t04a0)  t0__t0_2a0
+       a1_ne_0_b_l1
+       r__r_2t0
+       MILLIRETN
+LSYM(e_3t0)    a1_ne_0_b_l0
+       t0__3t0
+       MILLIRET
+       r__r_t0
+LSYM(e_4t0)    a1_ne_0_b_l1
+       r__r_4t0
+       MILLIRETN
+LSYM(e_4t0a0)  a1_ne_0_b_l0
+       t0__4t0_a0
+       MILLIRET
+       r__r_t0
+LSYM(e4t08a0)  t0__t0_2a0
+       a1_ne_0_b_l1
+       r__r_4t0
+       MILLIRETN
+LSYM(e_5t0)    a1_ne_0_b_l0
+       t0__5t0
+       MILLIRET
+       r__r_t0
+LSYM(e_8t0)    a1_ne_0_b_l1
+       r__r_8t0
+       MILLIRETN
+LSYM(e_8t0a0)  a1_ne_0_b_l0
+       t0__8t0_a0
+       MILLIRET
+       r__r_t0
+
+       .procend
+       .end
+#endif
diff --git a/arch/parisc/lib/milli/remI.S b/arch/parisc/lib/milli/remI.S
new file mode 100644 (file)
index 0000000..63bc094
--- /dev/null
@@ -0,0 +1,185 @@
+/* 32 and 64-bit millicode, original author Hewlett-Packard
+   adapted for gcc by Paul Bame <bame@debian.org>
+   and Alan Modra <alan@linuxcare.com.au>.
+
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This file is part of GCC and is released under the terms of
+   of the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+   See the file COPYING in the top-level GCC source directory for a copy
+   of the license.  */
+
+#include "milli.h"
+
+#ifdef L_remI
+/* ROUTINE:    $$remI
+
+   DESCRIPTION:
+   .   $$remI returns the remainder of the division of two signed 32-bit
+   .   integers.  The sign of the remainder is the same as the sign of
+   .   the dividend.
+
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   arg1 == divisor
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 = destroyed
+   .   arg1 = destroyed
+   .   ret1 = remainder
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   = undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions:  DIVIDE BY ZERO
+   .   Changes memory at the following places:  NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable
+   .   Does not create a stack frame
+   .   Is usable for internal or external microcode
+
+   DISCUSSION:
+   .   Calls other millicode routines via mrp:  NONE
+   .   Calls other millicode routines:  NONE  */
+
+RDEFINE(tmp,r1)
+RDEFINE(retreg,ret1)
+
+       SUBSPA_MILLI
+       ATTR_MILLI
+       .proc
+       .callinfo millicode
+       .entry
+GSYM($$remI)
+GSYM($$remoI)
+       .export $$remI,MILLICODE
+       .export $$remoI,MILLICODE
+       ldo             -1(arg1),tmp            /*  is there at most one bit set ? */
+       and,<>          arg1,tmp,r0             /*  if not, don't use power of 2 */
+       addi,>          0,arg1,r0               /*  if denominator > 0, use power */
+                                               /*  of 2 */
+       b,n             LREF(neg_denom)
+LSYM(pow2)
+       comb,>,n        0,arg0,LREF(neg_num)    /*  is numerator < 0 ? */
+       and             arg0,tmp,retreg         /*  get the result */
+       MILLIRETN
+LSYM(neg_num)
+       subi            0,arg0,arg0             /*  negate numerator */
+       and             arg0,tmp,retreg         /*  get the result */
+       subi            0,retreg,retreg         /*  negate result */
+       MILLIRETN
+LSYM(neg_denom)
+       addi,<          0,arg1,r0               /*  if arg1 >= 0, it's not power */
+                                               /*  of 2 */
+       b,n             LREF(regular_seq)
+       sub             r0,arg1,tmp             /*  make denominator positive */
+       comb,=,n        arg1,tmp,LREF(regular_seq) /*  test against 0x80000000 and 0 */
+       ldo             -1(tmp),retreg          /*  is there at most one bit set ? */
+       and,=           tmp,retreg,r0           /*  if not, go to regular_seq */
+       b,n             LREF(regular_seq)
+       comb,>,n        0,arg0,LREF(neg_num_2)  /*  if arg0 < 0, negate it  */
+       and             arg0,retreg,retreg
+       MILLIRETN
+LSYM(neg_num_2)
+       subi            0,arg0,tmp              /*  test against 0x80000000 */
+       and             tmp,retreg,retreg
+       subi            0,retreg,retreg
+       MILLIRETN
+LSYM(regular_seq)
+       addit,=         0,arg1,0                /*  trap if div by zero */
+       add,>=          0,arg0,retreg           /*  move dividend, if retreg < 0, */
+       sub             0,retreg,retreg         /*    make it positive */
+       sub             0,arg1, tmp             /*  clear carry,  */
+                                               /*    negate the divisor */
+       ds              0, tmp,0                /*  set V-bit to the comple- */
+                                               /*    ment of the divisor sign */
+       or              0,0, tmp                /*  clear  tmp */
+       add             retreg,retreg,retreg    /*  shift msb bit into carry */
+       ds               tmp,arg1, tmp          /*  1st divide step, if no carry */
+                                               /*    out, msb of quotient = 0 */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+LSYM(t1)
+       ds               tmp,arg1, tmp          /*  2nd divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  3rd divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  4th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  5th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  6th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  7th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  8th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  9th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  10th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  11th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  12th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  13th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  14th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  15th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  16th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  17th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  18th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  19th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  20th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  21st divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  22nd divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  23rd divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  24th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  25th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  26th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  27th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  28th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  29th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  30th divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  31st divide step */
+       addc            retreg,retreg,retreg    /*  shift retreg with/into carry */
+       ds               tmp,arg1, tmp          /*  32nd divide step, */
+       addc            retreg,retreg,retreg    /*  shift last bit into retreg */
+       movb,>=,n        tmp,retreg,LREF(finish) /*  branch if pos.  tmp */
+       add,<           arg1,0,0                /*  if arg1 > 0, add arg1 */
+       add,tr           tmp,arg1,retreg        /*    for correcting remainder tmp */
+       sub              tmp,arg1,retreg        /*  else add absolute value arg1 */
+LSYM(finish)
+       add,>=          arg0,0,0                /*  set sign of remainder */
+       sub             0,retreg,retreg         /*    to sign of dividend */
+       MILLIRET
+       nop
+       .exit
+       .procend
+#ifdef milliext
+       .origin 0x00000200
+#endif
+       .end
+#endif
diff --git a/arch/parisc/lib/milli/remU.S b/arch/parisc/lib/milli/remU.S
new file mode 100644 (file)
index 0000000..c0a2d6e
--- /dev/null
@@ -0,0 +1,148 @@
+/* 32 and 64-bit millicode, original author Hewlett-Packard
+   adapted for gcc by Paul Bame <bame@debian.org>
+   and Alan Modra <alan@linuxcare.com.au>.
+
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This file is part of GCC and is released under the terms of
+   of the GNU General Public License as published by the Free Software
+   Foundation; either version 2, or (at your option) any later version.
+   See the file COPYING in the top-level GCC source directory for a copy
+   of the license.  */
+
+#include "milli.h"
+
+#ifdef L_remU
+/* ROUTINE:    $$remU
+   .   Single precision divide for remainder with unsigned binary integers.
+   .
+   .   The remainder must be dividend-(dividend/divisor)*divisor.
+   .   Divide by zero is trapped.
+
+   INPUT REGISTERS:
+   .   arg0 == dividend
+   .   arg1 == divisor
+   .   mrp  == return pc
+   .   sr0  == return space when called externally
+
+   OUTPUT REGISTERS:
+   .   arg0 =  undefined
+   .   arg1 =  undefined
+   .   ret1 =  remainder
+
+   OTHER REGISTERS AFFECTED:
+   .   r1   =  undefined
+
+   SIDE EFFECTS:
+   .   Causes a trap under the following conditions:  DIVIDE BY ZERO
+   .   Changes memory at the following places:  NONE
+
+   PERMISSIBLE CONTEXT:
+   .   Unwindable.
+   .   Does not create a stack frame.
+   .   Suitable for internal or external millicode.
+   .   Assumes the special millicode register conventions.
+
+   DISCUSSION:
+   .   Calls other millicode routines using mrp: NONE
+   .   Calls other millicode routines: NONE  */
+
+
+RDEFINE(temp,r1)
+RDEFINE(rmndr,ret1)    /*  r29 */
+       SUBSPA_MILLI
+       ATTR_MILLI
+       .export $$remU,millicode
+       .proc
+       .callinfo       millicode
+       .entry
+GSYM($$remU)
+       ldo     -1(arg1),temp           /*  is there at most one bit set ? */
+       and,=   arg1,temp,r0            /*  if not, don't use power of 2 */
+       b       LREF(regular_seq)
+       addit,= 0,arg1,r0               /*  trap on div by zero */
+       and     arg0,temp,rmndr         /*  get the result for power of 2 */
+       MILLIRETN
+LSYM(regular_seq)
+       comib,>=,n  0,arg1,LREF(special_case)
+       subi    0,arg1,rmndr            /*  clear carry, negate the divisor */
+       ds      r0,rmndr,r0             /*  set V-bit to 1 */
+       add     arg0,arg0,temp          /*  shift msb bit into carry */
+       ds      r0,arg1,rmndr           /*  1st divide step, if no carry */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  2nd divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  3rd divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  4th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  5th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  6th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  7th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  8th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  9th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  10th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  11th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  12th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  13th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  14th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  15th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  16th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  17th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  18th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  19th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  20th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  21st divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  22nd divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  23rd divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  24th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  25th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  26th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  27th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  28th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  29th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  30th divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  31st divide step */
+       addc    temp,temp,temp          /*  shift temp with/into carry */
+       ds      rmndr,arg1,rmndr                /*  32nd divide step, */
+       comiclr,<= 0,rmndr,r0
+         add   rmndr,arg1,rmndr        /*  correction */
+       MILLIRETN
+       nop
+
+/* Putting >= on the last DS and deleting COMICLR does not work!  */
+LSYM(special_case)
+       sub,>>= arg0,arg1,rmndr
+         copy  arg0,rmndr
+       MILLIRETN
+       nop
+       .exit
+       .procend
+       .end
+#endif
index e724b36..aa875fa 100644 (file)
@@ -607,7 +607,7 @@ void show_mem(void)
 
                                printk("Zone list for zone %d on node %d: ", j, i);
                                for (k = 0; zl->zones[k] != NULL; k++) 
-                                       printk("[%ld/%s] ", zone_to_nid(zl->zones[k]), zl->zones[k]->name);
+                                       printk("[%d/%s] ", zone_to_nid(zl->zones[k]), zl->zones[k]->name);
                                printk("\n");
                        }
                }
index c939fe8..6a79fe4 100644 (file)
@@ -216,7 +216,6 @@ config PPC_EARLY_DEBUG_BEAT
 config PPC_EARLY_DEBUG_44x
        bool "Early serial debugging for IBM/AMCC 44x CPUs"
        depends on 44x
-       select PPC_UDBG_16550
        help
          Select this to enable early debugging for IBM 44x chips via the
          inbuilt serial port.
index a88ae3d..cb2fb50 100644 (file)
                        interrupt-parent = <&MAL0>;
                        interrupts = <0 1 2 3 4>;
                        #interrupt-cells = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
                        interrupt-map = </*TXEOB*/ 0 &UIC0 a 4
                                        /*RXEOB*/ 1 &UIC0 b 4
                                        /*SERR*/  2 &UIC1 0 4
                                        /*TXDE*/  3 &UIC1 1 4
-                                       /*RXDE*/  4 &UIC1 3 4>;
+                                       /*RXDE*/  4 &UIC1 2 4>;
                };
 
                POB0: opb {
                        };
 
                        EMAC0: ethernet@ef600e00 {
+                               linux,network-index = <0>;
                                device_type = "network";
                                compatible = "ibm,emac-440ep", "ibm,emac-440gp", "ibm,emac";
                                interrupt-parent = <&UIC1>;
                                rx-fifo-size = <1000>;
                                tx-fifo-size = <800>;
                                phy-mode = "rmii";
-                               phy-map = <00000001>;
+                               phy-map = <00000000>;
                                zmii-device = <&ZMII0>;
                                zmii-channel = <0>;
                        };
 
                        EMAC1: ethernet@ef600f00 {
+                               linux,network-index = <1>;
                                device_type = "network";
                                compatible = "ibm,emac-440ep", "ibm,emac-440gp", "ibm,emac";
                                interrupt-parent = <&UIC1>;
                                rx-fifo-size = <1000>;
                                tx-fifo-size = <800>;
                                phy-mode = "rmii";
-                               phy-map = <00000001>;
+                               phy-map = <00000000>;
                                zmii-device = <&ZMII0>;
                                zmii-channel = <1>;
                        };
index bc45f5f..6731763 100644 (file)
                };
 
                gpt@600 {       // General Purpose Timer
-                       compatible = "mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200-gpt";
                        cell-index = <0>;
                        reg = <600 10>;
                        interrupts = <1 9 0>;
                        interrupt-parent = <&mpc5200_pic>;
-                       has-wdt;
+                       fsl,has-wdt;
                };
 
                gpt@610 {       // General Purpose Timer
-                       compatible = "mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200-gpt";
                        cell-index = <1>;
                        reg = <610 10>;
                        interrupts = <1 a 0>;
@@ -89,8 +87,7 @@
                };
 
                gpt@620 {       // General Purpose Timer
-                       compatible = "mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200-gpt";
                        cell-index = <2>;
                        reg = <620 10>;
                        interrupts = <1 b 0>;
@@ -98,8 +95,7 @@
                };
 
                gpt@630 {       // General Purpose Timer
-                       compatible = "mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200-gpt";
                        cell-index = <3>;
                        reg = <630 10>;
                        interrupts = <1 c 0>;
                };
 
                gpt@640 {       // General Purpose Timer
-                       compatible = "mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200-gpt";
                        cell-index = <4>;
                        reg = <640 10>;
                        interrupts = <1 d 0>;
                };
 
                gpt@650 {       // General Purpose Timer
-                       compatible = "mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200-gpt";
                        cell-index = <5>;
                        reg = <650 10>;
                        interrupts = <1 e 0>;
                };
 
                gpt@660 {       // General Purpose Timer
-                       compatible = "mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200-gpt";
                        cell-index = <6>;
                        reg = <660 10>;
                        interrupts = <1 f 0>;
                };
 
                gpt@670 {       // General Purpose Timer
-                       compatible = "mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200-gpt";
                        cell-index = <7>;
                        reg = <670 10>;
                        interrupts = <1 10 0>;
index 6582c9a..b540388 100644 (file)
                };
 
                gpt@600 {       // General Purpose Timer
-                       compatible = "mpc5200b-gpt","mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        cell-index = <0>;
                        reg = <600 10>;
                        interrupts = <1 9 0>;
                        interrupt-parent = <&mpc5200_pic>;
-                       has-wdt;
+                       fsl,has-wdt;
                };
 
                gpt@610 {       // General Purpose Timer
-                       compatible = "mpc5200b-gpt","mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        cell-index = <1>;
                        reg = <610 10>;
                        interrupts = <1 a 0>;
@@ -89,8 +87,7 @@
                };
 
                gpt@620 {       // General Purpose Timer
-                       compatible = "mpc5200b-gpt","mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        cell-index = <2>;
                        reg = <620 10>;
                        interrupts = <1 b 0>;
@@ -98,8 +95,7 @@
                };
 
                gpt@630 {       // General Purpose Timer
-                       compatible = "mpc5200b-gpt","mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        cell-index = <3>;
                        reg = <630 10>;
                        interrupts = <1 c 0>;
                };
 
                gpt@640 {       // General Purpose Timer
-                       compatible = "mpc5200b-gpt","mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        cell-index = <4>;
                        reg = <640 10>;
                        interrupts = <1 d 0>;
                };
 
                gpt@650 {       // General Purpose Timer
-                       compatible = "mpc5200b-gpt","mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        cell-index = <5>;
                        reg = <650 10>;
                        interrupts = <1 e 0>;
                };
 
                gpt@660 {       // General Purpose Timer
-                       compatible = "mpc5200b-gpt","mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        cell-index = <6>;
                        reg = <660 10>;
                        interrupts = <1 f 0>;
                };
 
                gpt@670 {       // General Purpose Timer
-                       compatible = "mpc5200b-gpt","mpc5200-gpt";
-                       device_type = "gpt";
+                       compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
                        cell-index = <7>;
                        reg = <670 10>;
                        interrupts = <1 10 0>;
index 36be75b..8833dfe 100644 (file)
                                reg = <ef600d00 c>;
                        };
 
+                       RGMII0: emac-rgmii@ef601000 {
+                               device_type = "rgmii-interface";
+                               compatible = "ibm,rgmii-440epx", "ibm,rgmii";
+                               reg = <ef601000 8>;
+                       };
+
                        EMAC0: ethernet@ef600e00 {
                                linux,network-index = <0>;
                                device_type = "network";
                                max-frame-size = <5dc>;
                                rx-fifo-size = <1000>;
                                tx-fifo-size = <800>;
-                               phy-mode = "rmii";
+                               phy-mode = "rgmii";
                                phy-map = <00000000>;
                                zmii-device = <&ZMII0>;
                                zmii-channel = <0>;
+                               rgmii-device = <&RGMII0>;
+                               rgmii-channel = <0>;
                        };
 
                        EMAC1: ethernet@ef600f00 {
                                max-frame-size = <5dc>;
                                rx-fifo-size = <1000>;
                                tx-fifo-size = <800>;
-                               phy-mode = "rmii";
+                               phy-mode = "rgmii";
                                phy-map = <00000000>;
                                zmii-device = <&ZMII0>;
                                zmii-channel = <1>;
+                               rgmii-device = <&RGMII0>;
+                               rgmii-channel = <1>;
                        };
                };
        };
index ec54f4e..fa681f5 100644 (file)
                MAL: mcmal {
                        compatible = "ibm,mcmal-405gp", "ibm,mcmal";
                        dcr-reg = <180 62>;
-                       num-tx-chans = <2>;
+                       num-tx-chans = <1>;
                        num-rx-chans = <1>;
                        interrupt-parent = <&UIC0>;
-                       interrupts = <a 4 b 4 c 4 d 4 e 4>;
+                       interrupts = <
+                               b 4 /* TXEOB */
+                               c 4 /* RXEOB */
+                               a 4 /* SERR */
+                               d 4 /* TXDE */
+                               e 4 /* RXDE */>;
                };
 
                POB0: opb {
                                compatible = "ibm,emac-405gp", "ibm,emac";
                                interrupt-parent = <&UIC0>;
                                interrupts = <9 4 f 4>;
+                               local-mac-address = [000000000000]; /* Filled in by zImage */
                                reg = <ef600800 70>;
                                mal-device = <&MAL>;
-                               mal-tx-channel = <0 1>;
+                               mal-tx-channel = <0>;
                                mal-rx-channel = <0>;
                                cell-index = <0>;
                                max-frame-size = <5dc>;
index 3adf2d0..bb2c309 100644 (file)
@@ -57,8 +57,8 @@ void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
        }
 
        /* setup the timebase clock to tick at the cpu frequency */
-       cpc0_cr1 = cpc0_cr1 & ~ 0x00800000;
-       mtdcr(DCRN_CPC0_CR1, cpc0_cr1);
+       cpc0_cr1 = cpc0_cr1 & ~0x00800000;
+       mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
        tb = cpu;
 
        dt_fixup_cpu_clocks(cpu, tb, 0);
@@ -109,6 +109,7 @@ static void walnut_flashsel_fixup(void)
        setprop(sram, "reg", reg_sram, sizeof(reg_sram));
 }
 
+#define WALNUT_OPENBIOS_MAC_OFF 0xfffffe0b
 static void walnut_fixups(void)
 {
        ibm4xx_fixup_memsize();
@@ -116,6 +117,7 @@ static void walnut_fixups(void)
        ibm4xx_quiesce_eth((u32 *)0xef600800, NULL);
        ibm4xx_fixup_ebc_ranges("/plb/ebc");
        walnut_flashsel_fixup();
+       dt_fixup_mac_addresses((u8 *) WALNUT_OPENBIOS_MAC_OFF);
 }
 
 void platform_init(void)
index d22fed6..844808e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc1
-# Fri Aug  3 10:46:53 2007
+# Linux kernel version: 2.6.23
+# Fri Oct 19 09:01:11 2007
 #
 # CONFIG_PPC64 is not set
 
@@ -22,8 +22,13 @@ CONFIG_PHYS_64BIT=y
 # CONFIG_PPC_MM_SLICES is not set
 CONFIG_NOT_COHERENT_CACHE=y
 CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
 CONFIG_PPC_MERGE=y
 CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_IRQ_PER_CPU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -67,6 +72,8 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
 CONFIG_BLK_DEV_INITRD=y
@@ -87,7 +94,6 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -133,6 +139,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_PQ2ADS is not set
 CONFIG_BAMBOO=y
 # CONFIG_EBONY is not set
+# CONFIG_SEQUOIA is not set
 CONFIG_440EP=y
 CONFIG_IBM440EP_ERR42=y
 # CONFIG_MPIC is not set
@@ -146,11 +153,16 @@ CONFIG_IBM440EP_ERR42=y
 # CONFIG_GENERIC_IOMAP is not set
 # CONFIG_CPU_FREQ is not set
 # CONFIG_CPM2 is not set
+# CONFIG_FSL_ULI1575 is not set
 
 #
 # Kernel options
 #
 # CONFIG_HIGHMEM is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
 # CONFIG_HZ_300 is not set
@@ -172,6 +184,7 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
@@ -197,10 +210,6 @@ CONFIG_PCI_SYSCALL=y
 CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
 # CONFIG_PCCARD is not set
 # CONFIG_HOTPLUG_PCI is not set
 
@@ -215,7 +224,7 @@ CONFIG_ARCH_SUPPORTS_MSI=y
 CONFIG_HIGHMEM_START=0xfe000000
 CONFIG_LOWMEM_SIZE=0x30000000
 CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
+CONFIG_TASK_SIZE=0xc0000000
 CONFIG_CONSISTENT_START=0xff100000
 CONFIG_CONSISTENT_SIZE=0x00200000
 CONFIG_BOOT_LOAD=0x01000000
@@ -252,6 +261,7 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -309,6 +319,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
@@ -353,10 +364,6 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_SCSI_NETLINK is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
 # CONFIG_FUSION is not set
 
 #
@@ -375,12 +382,36 @@ CONFIG_NETDEVICES=y
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_IP1000 is not set
 # CONFIG_ARCNET is not set
-# CONFIG_NET_ETHERNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=128
+CONFIG_IBM_NEW_EMAC_TXB=64
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+CONFIG_IBM_NEW_EMAC_ZMII=y
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
 CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -388,6 +419,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -396,11 +428,14 @@ CONFIG_NETDEV_1000=y
 CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
 # CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
 # CONFIG_TR is not set
 
 #
@@ -463,14 +498,11 @@ CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_NVRAM is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
@@ -484,6 +516,13 @@ CONFIG_DEVPORT=y
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
 # Multifunction device drivers
@@ -500,16 +539,17 @@ CONFIG_DAB=y
 #
 # Graphics support
 #
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Display device support
 #
 # CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
-# CONFIG_FB is not set
-# CONFIG_FB_IBM_GXT4500 is not set
 
 #
 # Sound
@@ -535,19 +575,6 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 # CONFIG_EDAC is not set
 # CONFIG_RTC_CLASS is not set
 
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
 #
 # Userspace I/O
 #
@@ -600,7 +627,6 @@ CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -619,10 +645,7 @@ CONFIG_CRAMFS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
@@ -648,15 +671,7 @@ CONFIG_SUNRPC=y
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
 # CONFIG_UCC_SLOW is not set
 
@@ -709,6 +724,7 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_STACKOVERFLOW is not set
@@ -728,6 +744,7 @@ CONFIG_PPC_EARLY_DEBUG=y
 # CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set
 # CONFIG_PPC_EARLY_DEBUG_BEAT is not set
 CONFIG_PPC_EARLY_DEBUG_44x=y
+# CONFIG_PPC_EARLY_DEBUG_CPM is not set
 CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0xef600300
 CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x0
 
@@ -736,6 +753,7 @@ CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x0
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=y
@@ -755,6 +773,7 @@ CONFIG_CRYPTO_ECB=y
 CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=y
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
 # CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_FCRYPT is not set
@@ -768,9 +787,12 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
 # CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_PPC_CLOCK is not set
index 35a95dd..d3ef642 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc4
-# Thu Aug 30 16:34:11 2007
+# Linux kernel version: 2.6.23
+# Thu Oct 18 08:01:57 2007
 #
 # CONFIG_PPC64 is not set
 
@@ -21,8 +21,13 @@ CONFIG_PHYS_64BIT=y
 # CONFIG_PPC_MM_SLICES is not set
 CONFIG_NOT_COHERENT_CACHE=y
 CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
 CONFIG_PPC_MERGE=y
 CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_IRQ_PER_CPU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -66,6 +71,8 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
 CONFIG_BLK_DEV_INITRD=y
@@ -86,7 +93,6 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -130,7 +136,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PQ2ADS is not set
+# CONFIG_BAMBOO is not set
 CONFIG_EBONY=y
+# CONFIG_SEQUOIA is not set
 CONFIG_440GP=y
 # CONFIG_MPIC is not set
 # CONFIG_MPIC_WEIRD is not set
@@ -149,6 +157,10 @@ CONFIG_440GP=y
 # Kernel options
 #
 # CONFIG_HIGHMEM is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
 # CONFIG_HZ_300 is not set
@@ -170,6 +182,7 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
@@ -194,10 +207,6 @@ CONFIG_PCI_SYSCALL=y
 CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
 # CONFIG_PCCARD is not set
 # CONFIG_HOTPLUG_PCI is not set
 
@@ -212,7 +221,7 @@ CONFIG_ARCH_SUPPORTS_MSI=y
 CONFIG_HIGHMEM_START=0xfe000000
 CONFIG_LOWMEM_SIZE=0x30000000
 CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
+CONFIG_TASK_SIZE=0xc0000000
 CONFIG_CONSISTENT_START=0xff100000
 CONFIG_CONSISTENT_SIZE=0x00200000
 CONFIG_BOOT_LOAD=0x01000000
@@ -249,6 +258,7 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -306,6 +316,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
@@ -332,6 +343,7 @@ CONFIG_MTD_BLOCK=y
 # 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
@@ -364,6 +376,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
 CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -423,10 +436,6 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_SCSI_NETLINK is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
 # CONFIG_FUSION is not set
 
 #
@@ -443,12 +452,36 @@ CONFIG_NETDEVICES=y
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_IP1000 is not set
 # CONFIG_ARCNET is not set
-# CONFIG_NET_ETHERNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=128
+CONFIG_IBM_NEW_EMAC_TXB=64
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+CONFIG_IBM_NEW_EMAC_ZMII=y
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
 CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -456,6 +489,7 @@ CONFIG_NETDEV_1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -464,11 +498,14 @@ CONFIG_NETDEV_1000=y
 CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
 # CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
 # CONFIG_TR is not set
 
 #
@@ -537,8 +574,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
@@ -553,6 +588,12 @@ CONFIG_DEVPORT=y
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
 #
 # Multifunction device drivers
 #
@@ -568,16 +609,17 @@ CONFIG_DEVPORT=y
 #
 # Graphics support
 #
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# 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
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_FB_IBM_GXT4500 is not set
 
 #
 # Sound
@@ -603,19 +645,6 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 # CONFIG_EDAC is not set
 # CONFIG_RTC_CLASS is not set
 
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
 #
 # Userspace I/O
 #
@@ -668,7 +697,6 @@ CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -684,10 +712,12 @@ CONFIG_RAMFS=y
 CONFIG_JFFS2_FS=y
 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=y
@@ -696,10 +726,7 @@ CONFIG_CRAMFS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
@@ -725,15 +752,7 @@ CONFIG_SUNRPC=y
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
 # CONFIG_UCC_SLOW is not set
 
@@ -787,6 +806,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_STACKOVERFLOW is not set
@@ -801,6 +821,7 @@ CONFIG_FORCED_INLINING=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=y
@@ -820,6 +841,7 @@ CONFIG_CRYPTO_ECB=y
 CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=y
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
 # CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_FCRYPT is not set
@@ -833,9 +855,12 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
 # CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
 # CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
index 7724292..02896ec 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc4
-# Wed Sep  5 12:06:37 2007
+# Linux kernel version: 2.6.23
+# Thu Oct 18 12:54:18 2007
 #
 # CONFIG_PPC64 is not set
 
@@ -18,8 +18,13 @@ CONFIG_4xx=y
 # CONFIG_PPC_MM_SLICES is not set
 CONFIG_NOT_COHERENT_CACHE=y
 CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
 CONFIG_PPC_MERGE=y
 CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_IRQ_PER_CPU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -63,6 +68,8 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
 CONFIG_BLK_DEV_INITRD=y
@@ -83,7 +90,6 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -127,7 +133,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_PPC_CELL is not set
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PQ2ADS is not set
+# CONFIG_KILAUEA is not set
 CONFIG_WALNUT=y
+# CONFIG_XILINX_VIRTEX_GENERIC_BOARD is not set
 CONFIG_405GP=y
 CONFIG_IBM405_ERR77=y
 CONFIG_IBM405_ERR51=y
@@ -148,6 +156,10 @@ CONFIG_IBM405_ERR51=y
 # Kernel options
 #
 # CONFIG_HIGHMEM is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
 # CONFIG_HZ_300 is not set
@@ -169,6 +181,7 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
@@ -177,6 +190,8 @@ CONFIG_VIRT_TO_BUS=y
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_CMDLINE_BOOL is not set
 # CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_HIBERNATION_UP_POSSIBLE=y
 CONFIG_SECCOMP=y
 CONFIG_WANT_DEVICE_TREE=y
 CONFIG_DEVICE_TREE="walnut.dts"
@@ -190,10 +205,6 @@ CONFIG_ZONE_DMA=y
 # CONFIG_PCI_DOMAINS is not set
 # CONFIG_PCI_SYSCALL is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
 # CONFIG_PCCARD is not set
 
 #
@@ -207,7 +218,7 @@ CONFIG_ZONE_DMA=y
 CONFIG_HIGHMEM_START=0xfe000000
 CONFIG_LOWMEM_SIZE=0x30000000
 CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
+CONFIG_TASK_SIZE=0xc0000000
 CONFIG_CONSISTENT_START=0xff100000
 CONFIG_CONSISTENT_SIZE=0x00200000
 CONFIG_BOOT_LOAD=0x00400000
@@ -244,6 +255,7 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -301,6 +313,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
@@ -328,6 +341,7 @@ CONFIG_MTD_BLOCK=m
 # 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
@@ -360,7 +374,6 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
 CONFIG_MTD_PHYSMAP_OF=y
-# CONFIG_MTD_WALNUT is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -419,7 +432,22 @@ CONFIG_NETDEVICES=y
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_NET_ETHERNET is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=128
+CONFIG_IBM_NEW_EMAC_TXB=64
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+CONFIG_IBM_NEW_EMAC_ZMII=y
+# 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_B44 is not set
 CONFIG_NETDEV_1000=y
 CONFIG_NETDEV_10000=y
 
@@ -497,6 +525,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
 #
 # Multifunction device drivers
 #
@@ -512,16 +546,15 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Graphics support
 #
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Display device support
 #
 # CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
-# CONFIG_FB is not set
-# CONFIG_FB_IBM_GXT4500 is not set
 
 #
 # Sound
@@ -545,19 +578,6 @@ CONFIG_USB_SUPPORT=y
 # CONFIG_EDAC is not set
 # CONFIG_RTC_CLASS is not set
 
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
 #
 # Userspace I/O
 #
@@ -610,7 +630,6 @@ CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -630,10 +649,7 @@ CONFIG_CRAMFS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
@@ -659,15 +675,7 @@ CONFIG_SUNRPC=y
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
 # CONFIG_UCC_SLOW is not set
 
@@ -720,6 +728,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_STACKOVERFLOW is not set
@@ -734,6 +743,7 @@ CONFIG_FORCED_INLINING=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=y
@@ -753,6 +763,7 @@ CONFIG_CRYPTO_ECB=y
 CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=y
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
 # CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_FCRYPT is not set
@@ -766,9 +777,12 @@ CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
 # CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_PPC_CLOCK is not set
index 9001104..14206e3 100644 (file)
@@ -161,8 +161,7 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
        int i;
 
        for_each_sg(sgl, sg, nents, i) {
-               sg->dma_address = (page_to_phys(sg->page) + sg->offset) |
-                       dma_direct_offset;
+               sg->dma_address = sg_phys(sg) | dma_direct_offset;
                sg->dma_length = sg->length;
        }
 
index 289d7e9..72fd871 100644 (file)
@@ -102,8 +102,7 @@ static int ibmebus_map_sg(struct device *dev,
        int i;
 
        for_each_sg(sgl, sg, nents, i) {
-               sg->dma_address = (dma_addr_t)page_address(sg->page)
-                       + sg->offset;
+               sg->dma_address = (dma_addr_t) sg_virt(sg);
                sg->dma_length = sg->length;
        }
 
index 306a6f7..2d0c9ef 100644 (file)
@@ -307,7 +307,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
                        continue;
                }
                /* Allocate iommu entries for that segment */
-               vaddr = (unsigned long)page_address(s->page) + s->offset;
+               vaddr = (unsigned long) sg_virt(s);
                npages = iommu_num_pages(vaddr, slen);
                entry = iommu_range_alloc(tbl, npages, &handle, mask >> IOMMU_PAGE_SHIFT, 0);
 
index 47b3b0a..8f6699f 100644 (file)
@@ -100,6 +100,7 @@ config 405GP
        bool
        select IBM405_ERR77
        select IBM405_ERR51
+       select IBM_NEW_EMAC_ZMII
 
 config 405EP
        bool
index 51f3ea4..8390cc1 100644 (file)
@@ -43,14 +43,14 @@ config 440EP
        bool
        select PPC_FPU
        select IBM440EP_ERR42
-#      select IBM_NEW_EMAC_ZMII
+       select IBM_NEW_EMAC_ZMII
 
 config 440EPX
        bool
        select PPC_FPU
-# Disabled until the new EMAC Driver is merged.
-#      select IBM_NEW_EMAC_EMAC4
-#      select IBM_NEW_EMAC_ZMII
+       select IBM_NEW_EMAC_EMAC4
+       select IBM_NEW_EMAC_RGMII
+       select IBM_NEW_EMAC_ZMII
 
 config 440GP
        bool
index 65b7ae4..25d2bfa 100644 (file)
@@ -145,6 +145,9 @@ static void __init lite5200_setup_arch(void)
        /* Some mpc5200 & mpc5200b related configuration */
        mpc5200_setup_xlb_arbiter();
 
+       /* Map wdt for mpc52xx_restart() */
+       mpc52xx_map_wdt();
+
 #ifdef CONFIG_PM
        mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
        mpc52xx_suspend.board_resume_finish = lite5200_resume_finish;
@@ -183,5 +186,6 @@ define_machine(lite5200) {
        .init           = mpc52xx_declare_of_platform_devices,
        .init_IRQ       = mpc52xx_init_irq,
        .get_irq        = mpc52xx_get_irq,
+       .restart        = mpc52xx_restart,
        .calibrate_decr = generic_calibrate_decr,
 };
index 3bc201e..9850685 100644 (file)
 #include <asm/prom.h>
 #include <asm/mpc52xx.h>
 
+/*
+ * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart().
+ * Permanent mapping is required because mpc52xx_restart() can be called
+ * from interrupt context while node mapping (which calls ioremap())
+ * cannot be used at such point.
+ */
+static volatile struct mpc52xx_gpt *mpc52xx_wdt = NULL;
 
-void __iomem *
-mpc52xx_find_and_map(const char *compatible)
+static void __iomem *
+mpc52xx_map_node(struct device_node *ofn)
 {
-       struct device_node *ofn;
        const u32 *regaddr_p;
        u64 regaddr64, size64;
 
-       ofn = of_find_compatible_node(NULL, NULL, compatible);
        if (!ofn)
                return NULL;
 
@@ -42,8 +47,23 @@ mpc52xx_find_and_map(const char *compatible)
 
        return ioremap((u32)regaddr64, (u32)size64);
 }
+
+void __iomem *
+mpc52xx_find_and_map(const char *compatible)
+{
+       return mpc52xx_map_node(
+               of_find_compatible_node(NULL, NULL, compatible));
+}
+
 EXPORT_SYMBOL(mpc52xx_find_and_map);
 
+void __iomem *
+mpc52xx_find_and_map_path(const char *path)
+{
+       return mpc52xx_map_node(of_find_node_by_path(path));
+}
+
+EXPORT_SYMBOL(mpc52xx_find_and_map_path);
 
 /**
  *     mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device
@@ -113,3 +133,46 @@ mpc52xx_declare_of_platform_devices(void)
                        "Error while probing of_platform bus\n");
 }
 
+void __init
+mpc52xx_map_wdt(void)
+{
+       const void *has_wdt;
+       struct device_node *np;
+
+       /* mpc52xx_wdt is mapped here and used in mpc52xx_restart,
+        * possibly from a interrupt context. wdt is only implement
+        * on a gpt0, so check has-wdt property before mapping.
+        */
+       for_each_compatible_node(np, NULL, "fsl,mpc5200-gpt") {
+               has_wdt = of_get_property(np, "fsl,has-wdt", NULL);
+               if (has_wdt) {
+                       mpc52xx_wdt = mpc52xx_map_node(np);
+                       return;
+               }
+       }
+       for_each_compatible_node(np, NULL, "mpc5200-gpt") {
+               has_wdt = of_get_property(np, "has-wdt", NULL);
+               if (has_wdt) {
+                       mpc52xx_wdt = mpc52xx_map_node(np);
+                       return;
+               }
+       }
+}
+
+void
+mpc52xx_restart(char *cmd)
+{
+       local_irq_disable();
+
+       /* Turn on the watchdog and wait for it to expire.
+        * It effectively does a reset. */
+       if (mpc52xx_wdt) {
+               out_be32(&mpc52xx_wdt->mode, 0x00000000);
+               out_be32(&mpc52xx_wdt->count, 0x000000ff);
+               out_be32(&mpc52xx_wdt->mode, 0x00009004);
+       } else
+               printk("mpc52xx_restart: Can't access wdt. "
+                       "Restart impossible, system halted.\n");
+
+       while (1);
+}
index 3c7325e..99684ea 100644 (file)
@@ -48,6 +48,7 @@ config 44x
        bool "AMCC 44x"
        select PPC_DCR_NATIVE
        select WANT_DEVICE_TREE
+       select PPC_UDBG_16550
 
 config E200
        bool "Freescale e200"
index 07e64b4..6405f4a 100644 (file)
@@ -628,9 +628,8 @@ static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sgl,
        int i;
 
        for_each_sg(sgl, sg, nents, i) {
-               int result = ps3_dma_map(dev->d_region,
-                       page_to_phys(sg->page) + sg->offset, sg->length,
-                                        &sg->dma_address, 0);
+               int result = ps3_dma_map(dev->d_region, sg_phys(sg),
+                                       sg->length, &sg->dma_address, 0);
 
                if (result) {
                        pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
index 48492a8..740ad73 100644 (file)
@@ -269,6 +269,7 @@ bcom_engine_init(void)
        int task;
        phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
        unsigned int tdt_size, ctx_size, var_size, fdt_size;
+       u16 regval;
 
        /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */
        tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
@@ -319,9 +320,11 @@ bcom_engine_init(void)
        /* Init 'always' initiator */
        out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
 
-       /* Disable COMM Bus Prefetch, apparently it's not reliable yet */
-       /* FIXME: This should be done on 5200 and not 5200B ... */
-       out_be16(&bcom_eng->regs->PtdCntrl, in_be16(&bcom_eng->regs->PtdCntrl) | 1);
+       /* Disable COMM Bus Prefetch on the original 5200; it's broken */
+       if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) {
+               regval = in_be16(&bcom_eng->regs->PtdCntrl);
+               out_be16(&bcom_eng->regs->PtdCntrl,  regval | 1);
+       }
 
        /* Init lock */
        spin_lock_init(&bcom_eng->lock);
index 487dc66..500497e 100644 (file)
@@ -13,6 +13,8 @@
 # modified by Cort (cort@cs.nmt.edu)
 #
 
+# KBUILD_CFLAGS used when building rest of boot (takes effect recursively)
+KBUILD_CFLAGS  += -fno-builtin -D__BOOTER__ -Iarch/$(ARCH)/boot/include
 HOSTCFLAGS     += -Iarch/$(ARCH)/boot/include
 
 BOOT_TARGETS   = zImage zImage.initrd znetboot znetboot.initrd
index 2aae23d..ece7b99 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22
-# Tue Jul 17 12:50:23 2007
+# Linux kernel version: 2.6.23
+# Mon Oct 22 12:10:44 2007
 #
 CONFIG_MMU=y
 CONFIG_ZONE_DMA=y
@@ -19,15 +19,11 @@ CONFIG_S390=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
@@ -42,7 +38,14 @@ CONFIG_AUDIT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_NS=y
+CONFIG_CGROUP_CPUACCT=y
 # CONFIG_CPUSETS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
 CONFIG_BLK_DEV_INITRD=y
@@ -63,7 +66,6 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -83,6 +85,7 @@ CONFIG_STOP_MACHINE=y
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
 CONFIG_BLK_DEV_BSG=y
+CONFIG_BLOCK_COMPAT=y
 
 #
 # IO Schedulers
@@ -108,7 +111,6 @@ CONFIG_64BIT=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=32
 CONFIG_HOTPLUG_CPU=y
-CONFIG_DEFAULT_MIGRATION_COST=1000000
 CONFIG_COMPAT=y
 CONFIG_SYSVIPC_COMPAT=y
 CONFIG_AUDIT_ARCH=y
@@ -143,9 +145,11 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
 CONFIG_HOLES_IN_ZONE=y
 
@@ -219,12 +223,14 @@ CONFIG_INET_TUNNEL=y
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
@@ -243,7 +249,48 @@ CONFIG_IPV6_SIT=y
 # CONFIG_IPV6_TUNNEL is not set
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_CONNTRACK_IPV4 is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
 # CONFIG_IP_DCCP is not set
 CONFIG_IP_SCTP=m
 # CONFIG_SCTP_DBG_MSG is not set
@@ -263,12 +310,7 @@ CONFIG_SCTP_HMAC_MD5=y
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
 CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_FIFO=y
 
 #
 # Queueing/Scheduling
@@ -306,10 +348,12 @@ CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_POLICE=y
 # CONFIG_NET_ACT_GACT is not set
 # CONFIG_NET_ACT_MIRRED is not set
+CONFIG_NET_ACT_NAT=m
 # CONFIG_NET_ACT_PEDIT is not set
 # CONFIG_NET_ACT_SIMP is not set
 CONFIG_NET_CLS_POLICE=y
 # CONFIG_NET_CLS_IND is not set
+CONFIG_NET_SCH_FIFO=y
 
 #
 # Network testing
@@ -329,6 +373,7 @@ CONFIG_CCW=y
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
@@ -400,17 +445,11 @@ CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 # CONFIG_SCSI_SAS_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_ZFCP=y
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=m
@@ -429,7 +468,9 @@ CONFIG_DM_ZERO=y
 CONFIG_DM_MULTIPATH=y
 # CONFIG_DM_MULTIPATH_EMC is not set
 # CONFIG_DM_MULTIPATH_RDAC is not set
+# CONFIG_DM_MULTIPATH_HP is not set
 # CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_IFB is not set
@@ -438,8 +479,13 @@ CONFIG_BONDING=m
 # CONFIG_MACVLAN is not set
 CONFIG_EQUALIZER=m
 CONFIG_TUN=m
+CONFIG_VETH=m
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII 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_NETDEV_1000=y
 CONFIG_NETDEV_10000=y
 # CONFIG_TR is not set
@@ -473,7 +519,6 @@ CONFIG_CCWGROUP=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_WATCHDOG is not set
 CONFIG_HW_RANDOM=m
 # CONFIG_R3964 is not set
 CONFIG_RAW_DRIVER=m
@@ -490,7 +535,6 @@ CONFIG_TN3270_CONSOLE=y
 CONFIG_TN3215=y
 CONFIG_TN3215_CONSOLE=y
 CONFIG_CCW_CONSOLE=y
-CONFIG_SCLP=y
 CONFIG_SCLP_TTY=y
 CONFIG_SCLP_CONSOLE=y
 CONFIG_SCLP_VT220_TTY=y
@@ -514,6 +558,11 @@ CONFIG_S390_TAPE_34XX=m
 CONFIG_MONWRITER=m
 CONFIG_S390_VMUR=m
 # CONFIG_POWER_SUPPLY is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
 
 #
 # File systems
@@ -569,7 +618,6 @@ CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
 CONFIG_CONFIGFS_FS=m
 
 #
@@ -588,10 +636,7 @@ CONFIG_CONFIGFS_FS=m
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
@@ -638,27 +683,13 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 # CONFIG_SYSV68_PARTITION is not set
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
-
-#
-# Distributed Lock Manager
-#
 CONFIG_DLM=m
 # CONFIG_DLM_DEBUG is not set
-
-#
-# Instrumentation Support
-#
-
-#
-# Profiling support
-#
+CONFIG_INSTRUMENTATION=y
 # CONFIG_PROFILING is not set
 CONFIG_KPROBES=y
+# CONFIG_MARKERS is not set
 
 #
 # Kernel hacking
@@ -682,6 +713,7 @@ CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_LOCK_ALLOC is not set
 # CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -694,14 +726,17 @@ CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_LKDTM is not set
 # CONFIG_FAULT_INJECTION is not set
+CONFIG_SAMPLES=y
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=m
 CONFIG_CRYPTO_BLKCIPHER=y
 CONFIG_CRYPTO_HASH=m
 CONFIG_CRYPTO_MANAGER=y
@@ -720,6 +755,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
 # CONFIG_CRYPTO_CRYPTD is not set
 # CONFIG_CRYPTO_DES is not set
 CONFIG_CRYPTO_FCRYPT=m
@@ -733,11 +769,13 @@ CONFIG_CRYPTO_FCRYPT=m
 # CONFIG_CRYPTO_ARC4 is not set
 # CONFIG_CRYPTO_KHAZAD is not set
 # CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_SEED=m
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_CRC32C is not set
 CONFIG_CRYPTO_CAMELLIA=m
 # CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_AUTHENC=m
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_SHA1_S390 is not set
 # CONFIG_CRYPTO_SHA256_S390 is not set
@@ -755,5 +793,6 @@ CONFIG_BITREVERSE=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=m
+CONFIG_CRC7=m
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
index 66b5190..ce0856d 100644 (file)
@@ -648,6 +648,8 @@ static int dump_set_type(enum dump_type type)
        case DUMP_TYPE_CCW:
                if (MACHINE_IS_VM)
                        dump_method = DUMP_METHOD_CCW_VM;
+               else if (diag308_set_works)
+                       dump_method = DUMP_METHOD_CCW_DIAG;
                else
                        dump_method = DUMP_METHOD_CCW_CIO;
                break;
index 70c5737..96492cf 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/timer.h>
+#include <asm/cpu.h>
 
 asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
 
@@ -91,6 +92,14 @@ EXPORT_SYMBOL(unregister_idle_notifier);
 
 void do_monitor_call(struct pt_regs *regs, long interruption_code)
 {
+       struct s390_idle_data *idle;
+
+       idle = &__get_cpu_var(s390_idle);
+       spin_lock(&idle->lock);
+       idle->idle_time += get_clock() - idle->idle_enter;
+       idle->in_idle = 0;
+       spin_unlock(&idle->lock);
+
        /* disable monitor call class 0 */
        __ctl_clear_bit(8, 15);
 
@@ -105,6 +114,7 @@ extern void s390_handle_mcck(void);
 static void default_idle(void)
 {
        int cpu, rc;
+       struct s390_idle_data *idle;
 
        /* CPU is going idle. */
        cpu = smp_processor_id();
@@ -142,6 +152,12 @@ static void default_idle(void)
                return;
        }
 
+       idle = &__get_cpu_var(s390_idle);
+       spin_lock(&idle->lock);
+       idle->idle_count++;
+       idle->in_idle = 1;
+       idle->idle_enter = get_clock();
+       spin_unlock(&idle->lock);
        trace_hardirqs_on();
        /* Wait for external, I/O or machine check interrupt. */
        __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
@@ -254,14 +270,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
        save_fp_regs(&current->thread.fp_regs);
        memcpy(&p->thread.fp_regs, &current->thread.fp_regs,
               sizeof(s390_fp_regs));
-        p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
        /* Set a new TLS ?  */
        if (clone_flags & CLONE_SETTLS)
                p->thread.acrs[0] = regs->gprs[6];
 #else /* CONFIG_64BIT */
        /* Save the fpu registers to new thread structure. */
        save_fp_regs(&p->thread.fp_regs);
-        p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
        /* Set a new TLS ?  */
        if (clone_flags & CLONE_SETTLS) {
                if (test_thread_flag(TIF_31BIT)) {
index 35edbef..1d97fe1 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/tlbflush.h>
 #include <asm/timer.h>
 #include <asm/lowcore.h>
+#include <asm/cpu.h>
 
 /*
  * An array with a pointer the lowcore of every CPU.
@@ -325,7 +326,7 @@ static void smp_ext_bitcall(int cpu, ec_bit_sig sig)
  */
 void smp_ptlb_callback(void *info)
 {
-       local_flush_tlb();
+       __tlb_flush_local();
 }
 
 void smp_ptlb_all(void)
@@ -494,6 +495,8 @@ int __cpuinit start_secondary(void *cpuvoid)
        return 0;
 }
 
+DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
+
 static void __init smp_create_idle(unsigned int cpu)
 {
        struct task_struct *p;
@@ -506,6 +509,7 @@ static void __init smp_create_idle(unsigned int cpu)
        if (IS_ERR(p))
                panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
        current_set[cpu] = p;
+       spin_lock_init(&(&per_cpu(s390_idle, cpu))->lock);
 }
 
 static int cpu_stopped(int cpu)
@@ -724,6 +728,7 @@ void __init smp_prepare_boot_cpu(void)
        cpu_set(0, cpu_online_map);
        S390_lowcore.percpu_offset = __per_cpu_offset[0];
        current_set[0] = current;
+       spin_lock_init(&(&__get_cpu_var(s390_idle))->lock);
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
@@ -756,22 +761,71 @@ static ssize_t show_capability(struct sys_device *dev, char *buf)
 }
 static SYSDEV_ATTR(capability, 0444, show_capability, NULL);
 
+static ssize_t show_idle_count(struct sys_device *dev, char *buf)
+{
+       struct s390_idle_data *idle;
+       unsigned long long idle_count;
+
+       idle = &per_cpu(s390_idle, dev->id);
+       spin_lock_irq(&idle->lock);
+       idle_count = idle->idle_count;
+       spin_unlock_irq(&idle->lock);
+       return sprintf(buf, "%llu\n", idle_count);
+}
+static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL);
+
+static ssize_t show_idle_time(struct sys_device *dev, char *buf)
+{
+       struct s390_idle_data *idle;
+       unsigned long long new_time;
+
+       idle = &per_cpu(s390_idle, dev->id);
+       spin_lock_irq(&idle->lock);
+       if (idle->in_idle) {
+               new_time = get_clock();
+               idle->idle_time += new_time - idle->idle_enter;
+               idle->idle_enter = new_time;
+       }
+       new_time = idle->idle_time;
+       spin_unlock_irq(&idle->lock);
+       return sprintf(buf, "%llu us\n", new_time >> 12);
+}
+static SYSDEV_ATTR(idle_time, 0444, show_idle_time, NULL);
+
+static struct attribute *cpu_attrs[] = {
+       &attr_capability.attr,
+       &attr_idle_count.attr,
+       &attr_idle_time.attr,
+       NULL,
+};
+
+static struct attribute_group cpu_attr_group = {
+       .attrs = cpu_attrs,
+};
+
 static int __cpuinit smp_cpu_notify(struct notifier_block *self,
                                    unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned int)(long)hcpu;
        struct cpu *c = &per_cpu(cpu_devices, cpu);
        struct sys_device *s = &c->sysdev;
+       struct s390_idle_data *idle;
 
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
-               if (sysdev_create_file(s, &attr_capability))
+               idle = &per_cpu(s390_idle, cpu);
+               spin_lock_irq(&idle->lock);
+               idle->idle_enter = 0;
+               idle->idle_time = 0;
+               idle->idle_count = 0;
+               spin_unlock_irq(&idle->lock);
+               if (sysfs_create_group(&s->kobj, &cpu_attr_group))
                        return NOTIFY_BAD;
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               sysdev_remove_file(s, &attr_capability);
+               sysfs_remove_group(&s->kobj, &cpu_attr_group);
                break;
        }
        return NOTIFY_OK;
@@ -784,6 +838,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = {
 static int __init topology_init(void)
 {
        int cpu;
+       int rc;
 
        register_cpu_notifier(&smp_cpu_nb);
 
@@ -796,7 +851,9 @@ static int __init topology_init(void)
                if (!cpu_online(cpu))
                        continue;
                s = &c->sysdev;
-               sysdev_create_file(s, &attr_capability);
+               rc = sysfs_create_group(&s->kobj, &cpu_attr_group);
+               if (rc)
+                       return rc;
        }
        return 0;
 }
index b159a9d..7e8efaa 100644 (file)
 #include <asm/futex.h>
 #include "uaccess.h"
 
+static inline pte_t *follow_table(struct mm_struct *mm, unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+
+       pgd = pgd_offset(mm, addr);
+       if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+               return NULL;
+
+       pud = pud_offset(pgd, addr);
+       if (pud_none(*pud) || unlikely(pud_bad(*pud)))
+               return NULL;
+
+       pmd = pmd_offset(pud, addr);
+       if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+               return NULL;
+
+       return pte_offset_map(pmd, addr);
+}
+
 static int __handle_fault(struct mm_struct *mm, unsigned long address,
                          int write_access)
 {
@@ -85,8 +106,6 @@ static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
 {
        struct mm_struct *mm = current->mm;
        unsigned long offset, pfn, done, size;
-       pgd_t *pgd;
-       pmd_t *pmd;
        pte_t *pte;
        void *from, *to;
 
@@ -94,15 +113,7 @@ static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
 retry:
        spin_lock(&mm->page_table_lock);
        do {
-               pgd = pgd_offset(mm, uaddr);
-               if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
-                       goto fault;
-
-               pmd = pmd_offset(pgd, uaddr);
-               if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
-                       goto fault;
-
-               pte = pte_offset_map(pmd, uaddr);
+               pte = follow_table(mm, uaddr);
                if (!pte || !pte_present(*pte) ||
                    (write_user && !pte_write(*pte)))
                        goto fault;
@@ -142,22 +153,12 @@ static unsigned long __dat_user_addr(unsigned long uaddr)
 {
        struct mm_struct *mm = current->mm;
        unsigned long pfn, ret;
-       pgd_t *pgd;
-       pmd_t *pmd;
        pte_t *pte;
        int rc;
 
        ret = 0;
 retry:
-       pgd = pgd_offset(mm, uaddr);
-       if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
-               goto fault;
-
-       pmd = pmd_offset(pgd, uaddr);
-       if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
-               goto fault;
-
-       pte = pte_offset_map(pmd, uaddr);
+       pte = follow_table(mm, uaddr);
        if (!pte || !pte_present(*pte))
                goto fault;
 
@@ -229,8 +230,6 @@ static size_t strnlen_user_pt(size_t count, const char __user *src)
        unsigned long uaddr = (unsigned long) src;
        struct mm_struct *mm = current->mm;
        unsigned long offset, pfn, done, len;
-       pgd_t *pgd;
-       pmd_t *pmd;
        pte_t *pte;
        size_t len_str;
 
@@ -240,15 +239,7 @@ static size_t strnlen_user_pt(size_t count, const char __user *src)
 retry:
        spin_lock(&mm->page_table_lock);
        do {
-               pgd = pgd_offset(mm, uaddr);
-               if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
-                       goto fault;
-
-               pmd = pmd_offset(pgd, uaddr);
-               if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
-                       goto fault;
-
-               pte = pte_offset_map(pmd, uaddr);
+               pte = follow_table(mm, uaddr);
                if (!pte || !pte_present(*pte))
                        goto fault;
 
@@ -308,8 +299,6 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
                      uaddr, done, size;
        unsigned long uaddr_from = (unsigned long) from;
        unsigned long uaddr_to = (unsigned long) to;
-       pgd_t *pgd_from, *pgd_to;
-       pmd_t *pmd_from, *pmd_to;
        pte_t *pte_from, *pte_to;
        int write_user;
 
@@ -317,39 +306,14 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
 retry:
        spin_lock(&mm->page_table_lock);
        do {
-               pgd_from = pgd_offset(mm, uaddr_from);
-               if (pgd_none(*pgd_from) || unlikely(pgd_bad(*pgd_from))) {
-                       uaddr = uaddr_from;
-                       write_user = 0;
-                       goto fault;
-               }
-               pgd_to = pgd_offset(mm, uaddr_to);
-               if (pgd_none(*pgd_to) || unlikely(pgd_bad(*pgd_to))) {
-                       uaddr = uaddr_to;
-                       write_user = 1;
-                       goto fault;
-               }
-
-               pmd_from = pmd_offset(pgd_from, uaddr_from);
-               if (pmd_none(*pmd_from) || unlikely(pmd_bad(*pmd_from))) {
-                       uaddr = uaddr_from;
-                       write_user = 0;
-                       goto fault;
-               }
-               pmd_to = pmd_offset(pgd_to, uaddr_to);
-               if (pmd_none(*pmd_to) || unlikely(pmd_bad(*pmd_to))) {
-                       uaddr = uaddr_to;
-                       write_user = 1;
-                       goto fault;
-               }
-
-               pte_from = pte_offset_map(pmd_from, uaddr_from);
+               pte_from = follow_table(mm, uaddr_from);
                if (!pte_from || !pte_present(*pte_from)) {
                        uaddr = uaddr_from;
                        write_user = 0;
                        goto fault;
                }
-               pte_to = pte_offset_map(pmd_to, uaddr_to);
+
+               pte_to = follow_table(mm, uaddr_to);
                if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
                        uaddr = uaddr_to;
                        write_user = 1;
index f95449b..6640193 100644 (file)
@@ -2,6 +2,6 @@
 # Makefile for the linux s390-specific parts of the memory manager.
 #
 
-obj-y   := init.o fault.o extmem.o mmap.o vmem.o
+obj-y   := init.o fault.o extmem.o mmap.o vmem.o pgtable.o
 obj-$(CONFIG_CMM) += cmm.o
 
index 3a25bbf..b234bb4 100644 (file)
@@ -81,6 +81,7 @@ void show_mem(void)
 static void __init setup_ro_region(void)
 {
        pgd_t *pgd;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        pte_t new_pte;
@@ -91,7 +92,8 @@ static void __init setup_ro_region(void)
 
        for (; address < end; address += PAGE_SIZE) {
                pgd = pgd_offset_k(address);
-               pmd = pmd_offset(pgd, address);
+               pud = pud_offset(pgd, address);
+               pmd = pmd_offset(pud, address);
                pte = pte_offset_kernel(pmd, address);
                new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
                *pte = new_pte;
@@ -103,32 +105,28 @@ static void __init setup_ro_region(void)
  */
 void __init paging_init(void)
 {
-       pgd_t *pg_dir;
-       int i;
-       unsigned long pgdir_k;
        static const int ssm_mask = 0x04000000L;
        unsigned long max_zone_pfns[MAX_NR_ZONES];
+       unsigned long pgd_type;
 
-       pg_dir = swapper_pg_dir;
-       
+       init_mm.pgd = swapper_pg_dir;
+       S390_lowcore.kernel_asce = __pa(init_mm.pgd) & PAGE_MASK;
 #ifdef CONFIG_64BIT
-       pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
-       for (i = 0; i < PTRS_PER_PGD; i++)
-               pgd_clear_kernel(pg_dir + i);
+       S390_lowcore.kernel_asce |= _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH;
+       pgd_type = _REGION3_ENTRY_EMPTY;
 #else
-       pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
-       for (i = 0; i < PTRS_PER_PGD; i++)
-               pmd_clear_kernel((pmd_t *)(pg_dir + i));
+       S390_lowcore.kernel_asce |= _ASCE_TABLE_LENGTH;
+       pgd_type = _SEGMENT_ENTRY_EMPTY;
 #endif
+       clear_table((unsigned long *) init_mm.pgd, pgd_type,
+                   sizeof(unsigned long)*2048);
        vmem_map_init();
        setup_ro_region();
 
-       S390_lowcore.kernel_asce = pgdir_k;
-
         /* enable virtual mapping in kernel mode */
-       __ctl_load(pgdir_k, 1, 1);
-       __ctl_load(pgdir_k, 7, 7);
-       __ctl_load(pgdir_k, 13, 13);
+       __ctl_load(S390_lowcore.kernel_asce, 1, 1);
+       __ctl_load(S390_lowcore.kernel_asce, 7, 7);
+       __ctl_load(S390_lowcore.kernel_asce, 13, 13);
        __raw_local_irq_ssm(ssm_mask);
 
        memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
new file mode 100644 (file)
index 0000000..e60e0ae
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  arch/s390/mm/pgtable.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/quicklist.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+
+#ifndef CONFIG_64BIT
+#define ALLOC_ORDER    1
+#else
+#define ALLOC_ORDER    2
+#endif
+
+unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
+{
+       struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
+
+       if (!page)
+               return NULL;
+       page->index = 0;
+       if (noexec) {
+               struct page *shadow = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
+               if (!shadow) {
+                       __free_pages(page, ALLOC_ORDER);
+                       return NULL;
+               }
+               page->index = page_to_phys(shadow);
+       }
+       return (unsigned long *) page_to_phys(page);
+}
+
+void crst_table_free(unsigned long *table)
+{
+       unsigned long *shadow = get_shadow_table(table);
+
+       if (shadow)
+               free_pages((unsigned long) shadow, ALLOC_ORDER);
+       free_pages((unsigned long) table, ALLOC_ORDER);
+}
+
+/*
+ * page table entry allocation/free routines.
+ */
+unsigned long *page_table_alloc(int noexec)
+{
+       struct page *page = alloc_page(GFP_KERNEL);
+       unsigned long *table;
+
+       if (!page)
+               return NULL;
+       page->index = 0;
+       if (noexec) {
+               struct page *shadow = alloc_page(GFP_KERNEL);
+               if (!shadow) {
+                       __free_page(page);
+                       return NULL;
+               }
+               table = (unsigned long *) page_to_phys(shadow);
+               clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
+               page->index = (addr_t) table;
+       }
+       table = (unsigned long *) page_to_phys(page);
+       clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
+       return table;
+}
+
+void page_table_free(unsigned long *table)
+{
+       unsigned long *shadow = get_shadow_pte(table);
+
+       if (shadow)
+               free_page((unsigned long) shadow);
+       free_page((unsigned long) table);
+
+}
index fd594d5..fb9c5a8 100644 (file)
@@ -73,31 +73,28 @@ static void __init_refok *vmem_alloc_pages(unsigned int order)
        return alloc_bootmem_pages((1 << order) * PAGE_SIZE);
 }
 
+#define vmem_pud_alloc()       ({ BUG(); ((pud_t *) NULL); })
+
 static inline pmd_t *vmem_pmd_alloc(void)
 {
-       pmd_t *pmd;
-       int i;
+       pmd_t *pmd = NULL;
 
-       pmd = vmem_alloc_pages(PMD_ALLOC_ORDER);
+#ifdef CONFIG_64BIT
+       pmd = vmem_alloc_pages(2);
        if (!pmd)
                return NULL;
-       for (i = 0; i < PTRS_PER_PMD; i++)
-               pmd_clear_kernel(pmd + i);
+       clear_table((unsigned long *) pmd, _SEGMENT_ENTRY_EMPTY, PAGE_SIZE*4);
+#endif
        return pmd;
 }
 
 static inline pte_t *vmem_pte_alloc(void)
 {
-       pte_t *pte;
-       pte_t empty_pte;
-       int i;
+       pte_t *pte = vmem_alloc_pages(0);
 
-       pte = vmem_alloc_pages(PTE_ALLOC_ORDER);
        if (!pte)
                return NULL;
-       pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
-       for (i = 0; i < PTRS_PER_PTE; i++)
-               pte[i] = empty_pte;
+       clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY, PAGE_SIZE);
        return pte;
 }
 
@@ -108,6 +105,7 @@ static int vmem_add_range(unsigned long start, unsigned long size)
 {
        unsigned long address;
        pgd_t *pg_dir;
+       pud_t *pu_dir;
        pmd_t *pm_dir;
        pte_t *pt_dir;
        pte_t  pte;
@@ -116,13 +114,21 @@ static int vmem_add_range(unsigned long start, unsigned long size)
        for (address = start; address < start + size; address += PAGE_SIZE) {
                pg_dir = pgd_offset_k(address);
                if (pgd_none(*pg_dir)) {
+                       pu_dir = vmem_pud_alloc();
+                       if (!pu_dir)
+                               goto out;
+                       pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+               }
+
+               pu_dir = pud_offset(pg_dir, address);
+               if (pud_none(*pu_dir)) {
                        pm_dir = vmem_pmd_alloc();
                        if (!pm_dir)
                                goto out;
-                       pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
+                       pud_populate_kernel(&init_mm, pu_dir, pm_dir);
                }
 
-               pm_dir = pmd_offset(pg_dir, address);
+               pm_dir = pmd_offset(pu_dir, address);
                if (pmd_none(*pm_dir)) {
                        pt_dir = vmem_pte_alloc();
                        if (!pt_dir)
@@ -148,6 +154,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
 {
        unsigned long address;
        pgd_t *pg_dir;
+       pud_t *pu_dir;
        pmd_t *pm_dir;
        pte_t *pt_dir;
        pte_t  pte;
@@ -155,9 +162,10 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
        pte_val(pte) = _PAGE_TYPE_EMPTY;
        for (address = start; address < start + size; address += PAGE_SIZE) {
                pg_dir = pgd_offset_k(address);
-               if (pgd_none(*pg_dir))
+               pu_dir = pud_offset(pg_dir, address);
+               if (pud_none(*pu_dir))
                        continue;
-               pm_dir = pmd_offset(pg_dir, address);
+               pm_dir = pmd_offset(pu_dir, address);
                if (pmd_none(*pm_dir))
                        continue;
                pt_dir = pte_offset_kernel(pm_dir, address);
@@ -174,6 +182,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
        unsigned long address, start_addr, end_addr;
        struct page *map_start, *map_end;
        pgd_t *pg_dir;
+       pud_t *pu_dir;
        pmd_t *pm_dir;
        pte_t *pt_dir;
        pte_t  pte;
@@ -188,13 +197,21 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
        for (address = start_addr; address < end_addr; address += PAGE_SIZE) {
                pg_dir = pgd_offset_k(address);
                if (pgd_none(*pg_dir)) {
+                       pu_dir = vmem_pud_alloc();
+                       if (!pu_dir)
+                               goto out;
+                       pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+               }
+
+               pu_dir = pud_offset(pg_dir, address);
+               if (pud_none(*pu_dir)) {
                        pm_dir = vmem_pmd_alloc();
                        if (!pm_dir)
                                goto out;
-                       pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
+                       pud_populate_kernel(&init_mm, pu_dir, pm_dir);
                }
 
-               pm_dir = pmd_offset(pg_dir, address);
+               pm_dir = pmd_offset(pu_dir, address);
                if (pmd_none(*pm_dir)) {
                        pt_dir = vmem_pte_alloc();
                        if (!pt_dir)
index 9c3ed88..97aa50d 100644 (file)
@@ -727,9 +727,8 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,
        BUG_ON(direction == PCI_DMA_NONE);
        /* IIep is write-through, not flushing. */
        for_each_sg(sgl, sg, nents, n) {
-               BUG_ON(page_address(sg->page) == NULL);
-               sg->dvma_address =
-                       virt_to_phys(page_address(sg->page)) + sg->offset;
+               BUG_ON(page_address(sg_page(sg)) == NULL);
+               sg->dvma_address = virt_to_phys(sg_virt(sg));
                sg->dvma_length = sg->length;
        }
        return nents;
@@ -748,9 +747,9 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,
        BUG_ON(direction == PCI_DMA_NONE);
        if (direction != PCI_DMA_TODEVICE) {
                for_each_sg(sgl, sg, nents, n) {
-                       BUG_ON(page_address(sg->page) == NULL);
+                       BUG_ON(page_address(sg_page(sg)) == NULL);
                        mmu_inval_dma_area(
-                           (unsigned long) page_address(sg->page),
+                           (unsigned long) page_address(sg_page(sg)),
                            (sg->length + PAGE_SIZE-1) & PAGE_MASK);
                }
        }
@@ -798,9 +797,9 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sgl, int
        BUG_ON(direction == PCI_DMA_NONE);
        if (direction != PCI_DMA_TODEVICE) {
                for_each_sg(sgl, sg, nents, n) {
-                       BUG_ON(page_address(sg->page) == NULL);
+                       BUG_ON(page_address(sg_page(sg)) == NULL);
                        mmu_inval_dma_area(
-                           (unsigned long) page_address(sg->page),
+                           (unsigned long) page_address(sg_page(sg)),
                            (sg->length + PAGE_SIZE-1) & PAGE_MASK);
                }
        }
@@ -814,9 +813,9 @@ void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sgl,
        BUG_ON(direction == PCI_DMA_NONE);
        if (direction != PCI_DMA_TODEVICE) {
                for_each_sg(sgl, sg, nents, n) {
-                       BUG_ON(page_address(sg->page) == NULL);
+                       BUG_ON(page_address(sg_page(sg)) == NULL);
                        mmu_inval_dma_area(
-                           (unsigned long) page_address(sg->page),
+                           (unsigned long) page_address(sg_page(sg)),
                            (sg->length + PAGE_SIZE-1) & PAGE_MASK);
                }
        }
index 375b4db..1666087 100644 (file)
@@ -144,7 +144,7 @@ static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus
        spin_lock_irqsave(&iounit->lock, flags);
        while (sz != 0) {
                --sz;
-               sg->dvma_address = iounit_get_area(iounit, (unsigned long)page_address(sg->page) + sg->offset, sg->length);
+               sg->dvma_address = iounit_get_area(iounit, sg_virt(sg), sg->length);
                sg->dvma_length = sg->length;
                sg = sg_next(sg);
        }
index 283656d..4b93427 100644 (file)
@@ -238,7 +238,7 @@ static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sb
        while (sz != 0) {
                --sz;
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               sg->dvma_address = iommu_get_one(sg->page, n, sbus) + sg->offset;
+               sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
                sg->dvma_length = (__u32) sg->length;
                sg = sg_next(sg);
        }
@@ -252,7 +252,7 @@ static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbu
        while (sz != 0) {
                --sz;
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               sg->dvma_address = iommu_get_one(sg->page, n, sbus) + sg->offset;
+               sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
                sg->dvma_length = (__u32) sg->length;
                sg = sg_next(sg);
        }
@@ -273,7 +273,7 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu
                 * XXX Is this a good assumption?
                 * XXX What if someone else unmaps it here and races us?
                 */
-               if ((page = (unsigned long) page_address(sg->page)) != 0) {
+               if ((page = (unsigned long) page_address(sg_page(sg))) != 0) {
                        for (i = 0; i < n; i++) {
                                if (page != oldpage) {  /* Already flushed? */
                                        flush_page_for_dma(page);
@@ -283,7 +283,7 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu
                        }
                }
 
-               sg->dvma_address = iommu_get_one(sg->page, n, sbus) + sg->offset;
+               sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
                sg->dvma_length = (__u32) sg->length;
                sg = sg_next(sg);
        }
index ee6708f..a2cc141 100644 (file)
@@ -1228,7 +1228,7 @@ static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *
 {
        while (sz != 0) {
                --sz;
-               sg->dvma_address = (__u32)sun4c_lockarea(page_address(sg->page) + sg->offset, sg->length);
+               sg->dvma_address = (__u32)sun4c_lockarea(sg_virt(sg), sg->length);
                sg->dvma_length = sg->length;
                sg = sg_next(sg);
        }
index c7a74e3..03c4e5c 100644 (file)
@@ -72,6 +72,10 @@ config ARCH_NO_VIRT_TO_BUS
 config OF
        def_bool y
 
+config GENERIC_HARDIRQS_NO__DO_IRQ
+       bool
+       def_bool y
+
 choice
        prompt "Kernel page size"
        default SPARC64_PAGE_SIZE_8KB
index 6c92a42..01159cb 100644 (file)
@@ -18,8 +18,6 @@ NEW_GCC := $(call cc-option-yn, -m64 -mcmodel=medlow)
 NEW_GAS := $(shell if $(LD) -V 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
 UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; )
 
-export NEW_GCC
-
 ifneq ($(NEW_GAS),y)
 AS             = sparc64-linux-as
 LD             = sparc64-linux-ld
@@ -58,8 +56,6 @@ core-y                                += arch/sparc64/kernel/ arch/sparc64/mm/
 core-$(CONFIG_SOLARIS_EMUL)    += arch/sparc64/solaris/
 core-y                         += arch/sparc64/math-emu/
 libs-y                         += arch/sparc64/prom/ arch/sparc64/lib/
-
-# FIXME: is drivers- right?
 drivers-$(CONFIG_OPROFILE)     += arch/sparc64/oprofile/
 
 boot := arch/sparc64/boot
index 1aa2c40..e023d4b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.23
-# Sat Oct 13 21:53:54 2007
+# Sun Oct 21 19:57:44 2007
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -49,6 +49,10 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=18
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_RELAY=y
 # CONFIG_BLK_DEV_INITRD is not set
@@ -145,7 +149,10 @@ CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_SPARSEMEM_MANUAL=y
 CONFIG_SPARSEMEM=y
 CONFIG_HAVE_MEMORY_PRESENT=y
-CONFIG_SPARSEMEM_STATIC=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSEMEM_VMEMMAP=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=0
@@ -275,10 +282,6 @@ CONFIG_VLAN_8021Q=m
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
 # CONFIG_NET_SCHED is not set
 
 #
@@ -372,8 +375,6 @@ CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_ONLYDISK=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_ALI15X3 is not set
@@ -401,6 +402,7 @@ CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_BLK_DEV_TC86C001 is not set
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_IDE_ARCH_OBSOLETE_INIT=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -441,6 +443,7 @@ CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 # CONFIG_SCSI_SAS_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
 CONFIG_SCSI_LOWLEVEL=y
 CONFIG_ISCSI_TCP=m
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
@@ -492,14 +495,8 @@ CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
 # CONFIG_DM_MULTIPATH is not set
 # CONFIG_DM_DELAY is not set
-
-#
-# Fusion MPT device support
-#
+# CONFIG_DM_UEVENT is not set
 # CONFIG_FUSION is not set
-# CONFIG_FUSION_SPI is not set
-# CONFIG_FUSION_FC is not set
-# CONFIG_FUSION_SAS is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -638,7 +635,6 @@ CONFIG_INPUT_MOUSEDEV_PSAUX=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
@@ -714,11 +710,9 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
@@ -786,8 +780,6 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_ABITUGURU3 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
@@ -795,12 +787,12 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ADT7470 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -836,6 +828,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_WATCHDOG is not set
 
 #
 # Sonics Silicon Backplane
@@ -858,12 +851,7 @@ CONFIG_SSB_POSSIBLE=y
 #
 # Graphics support
 #
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_DRM is not set
 # CONFIG_VGASTATE is not set
 # CONFIG_VIDEO_OUTPUT_CONTROL is not set
 CONFIG_FB=y
@@ -872,6 +860,7 @@ CONFIG_FB_DDC=y
 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
@@ -890,6 +879,7 @@ CONFIG_FB_TILEBLITTING=y
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
+# CONFIG_FB_UVESA is not set
 # CONFIG_FB_SBUS is not set
 # CONFIG_FB_XVR500 is not set
 # CONFIG_FB_XVR2500 is not set
@@ -915,6 +905,12 @@ CONFIG_FB_RADEON_I2C=y
 # CONFIG_FB_ARK is not set
 # CONFIG_FB_PM3 is not set
 # CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
 
 #
 # Console display driver support
@@ -1066,6 +1062,7 @@ CONFIG_AC97_BUS=m
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
 
 #
 # USB Input Devices
@@ -1186,19 +1183,6 @@ CONFIG_USB_STORAGE=m
 # CONFIG_INFINIBAND is not set
 # CONFIG_RTC_CLASS is not set
 
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
 #
 # Userspace I/O
 #
@@ -1275,7 +1259,6 @@ CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -1295,10 +1278,7 @@ CONFIG_RAMFS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
 # CONFIG_SMB_FS is not set
@@ -1313,10 +1293,6 @@ CONFIG_RAMFS=y
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
 CONFIG_SUN_PARTITION=y
-
-#
-# Native Language Support
-#
 CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
@@ -1357,18 +1333,12 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
-
-#
-# Instrumentation Support
-#
+CONFIG_INSTRUMENTATION=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
 CONFIG_KPROBES=y
+# CONFIG_MARKERS is not set
 
 #
 # Kernel hacking
@@ -1402,9 +1372,11 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_LKDTM is not set
 # CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_DEBUG_DCFLUSH is not set
 # CONFIG_STACK_DEBUG is not set
@@ -1417,6 +1389,7 @@ CONFIG_FORCED_INLINING=y
 CONFIG_KEYS=y
 # CONFIG_KEYS_DEBUG_PROC_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_XOR_BLOCKS=m
 CONFIG_ASYNC_CORE=m
 CONFIG_ASYNC_MEMCPY=m
index 112c46e..ef50d21 100644 (file)
@@ -39,12 +39,3 @@ else
     obj-y += sys_sunos32.o sunos_ioctl32.o
   endif
 endif
-
-ifneq ($(NEW_GCC),y)
-  CMODEL_CFLAG := -mmedlow
-else
-  CMODEL_CFLAG := -m64 -mcmodel=medlow
-endif
-
-head.o: head.S ttable.S itlb_miss.S dtlb_miss.S ktlb.S tsb.S \
-       etrap.S rtrap.S winfixup.S entry.S
index 29af777..070a484 100644 (file)
@@ -472,8 +472,7 @@ static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr,
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-#define SG_ENT_PHYS_ADDRESS(SG)        \
-       (__pa(page_address((SG)->page)) + (SG)->offset)
+#define SG_ENT_PHYS_ADDRESS(SG)        (__pa(sg_virt((SG))))
 
 static void fill_sg(iopte_t *iopte, struct scatterlist *sg,
                    int nused, int nelems,
@@ -565,9 +564,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
        /* Fast path single entry scatterlists. */
        if (nelems == 1) {
                sglist->dma_address =
-                       dma_4u_map_single(dev,
-                                         (page_address(sglist->page) +
-                                          sglist->offset),
+                       dma_4u_map_single(dev, sg_virt(sglist),
                                          sglist->length, direction);
                if (unlikely(sglist->dma_address == DMA_ERROR_CODE))
                        return 0;
index d7ca900..b70324e 100644 (file)
@@ -73,7 +73,7 @@ static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg,
 
        daddr = dma_sg->dma_address;
        sglen = sg->length;
-       sgaddr = (unsigned long) (page_address(sg->page) + sg->offset);
+       sgaddr = (unsigned long) sg_virt(sg);
        while (dlen > 0) {
                unsigned long paddr;
 
@@ -123,7 +123,7 @@ static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg,
                sg = sg_next(sg);
                if (--nents <= 0)
                        break;
-               sgaddr = (unsigned long) (page_address(sg->page) + sg->offset);
+               sgaddr = (unsigned long) sg_virt(sg);
                sglen = sg->length;
        }
        if (dlen < 0) {
@@ -191,7 +191,7 @@ void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int np
                        printk("sg(%d): page_addr(%p) off(%x) length(%x) "
                               "dma_address[%016x] dma_length[%016x]\n",
                               i,
-                              page_address(sg->page), sg->offset,
+                              page_address(sg_page(sg)), sg->offset,
                               sg->length,
                               sg->dma_address, sg->dma_length);
                }
@@ -207,15 +207,14 @@ unsigned long prepare_sg(struct scatterlist *sg, int nents)
        unsigned long prev;
        u32 dent_addr, dent_len;
 
-       prev  = (unsigned long) (page_address(sg->page) + sg->offset);
+       prev  = (unsigned long) sg_virt(sg);
        prev += (unsigned long) (dent_len = sg->length);
-       dent_addr = (u32) ((unsigned long)(page_address(sg->page) + sg->offset)
-                          & (IO_PAGE_SIZE - 1UL));
+       dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL));
        while (--nents) {
                unsigned long addr;
 
                sg = sg_next(sg);
-               addr = (unsigned long) (page_address(sg->page) + sg->offset);
+               addr = (unsigned long) sg_virt(sg);
                if (! VCONTIG(prev, addr)) {
                        dma_sg->dma_address = dent_addr;
                        dma_sg->dma_length = dent_len;
@@ -234,6 +233,11 @@ unsigned long prepare_sg(struct scatterlist *sg, int nents)
        dma_sg->dma_address = dent_addr;
        dma_sg->dma_length = dent_len;
 
+       if (dma_sg != sg) {
+               dma_sg = next_sg(dma_sg);
+               dma_sg->dma_length = 0;
+       }
+
        return ((unsigned long) dent_addr +
                (unsigned long) dent_len +
                (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT;
index 2c3bea2..30431bd 100644 (file)
@@ -257,8 +257,8 @@ struct irq_handler_data {
        unsigned long   imap;
 
        void            (*pre_handler)(unsigned int, void *, void *);
-       void            *pre_handler_arg1;
-       void            *pre_handler_arg2;
+       void            *arg1;
+       void            *arg2;
 };
 
 #ifdef CONFIG_SMP
@@ -346,7 +346,7 @@ static void sun4u_irq_disable(unsigned int virt_irq)
        }
 }
 
-static void sun4u_irq_end(unsigned int virt_irq)
+static void sun4u_irq_eoi(unsigned int virt_irq)
 {
        struct irq_handler_data *data = get_irq_chip_data(virt_irq);
        struct irq_desc *desc = irq_desc + virt_irq;
@@ -401,7 +401,7 @@ static void sun4v_irq_disable(unsigned int virt_irq)
                       "err(%d)\n", ino, err);
 }
 
-static void sun4v_irq_end(unsigned int virt_irq)
+static void sun4v_irq_eoi(unsigned int virt_irq)
 {
        unsigned int ino = virt_irq_table[virt_irq].dev_ino;
        struct irq_desc *desc = irq_desc + virt_irq;
@@ -478,7 +478,7 @@ static void sun4v_virq_disable(unsigned int virt_irq)
                       dev_handle, dev_ino, err);
 }
 
-static void sun4v_virq_end(unsigned int virt_irq)
+static void sun4v_virq_eoi(unsigned int virt_irq)
 {
        struct irq_desc *desc = irq_desc + virt_irq;
        unsigned long dev_handle, dev_ino;
@@ -498,33 +498,11 @@ static void sun4v_virq_end(unsigned int virt_irq)
                       dev_handle, dev_ino, err);
 }
 
-static void run_pre_handler(unsigned int virt_irq)
-{
-       struct irq_handler_data *data = get_irq_chip_data(virt_irq);
-       unsigned int ino;
-
-       ino = virt_irq_table[virt_irq].dev_ino;
-       if (likely(data->pre_handler)) {
-               data->pre_handler(ino,
-                                 data->pre_handler_arg1,
-                                 data->pre_handler_arg2);
-       }
-}
-
 static struct irq_chip sun4u_irq = {
        .typename       = "sun4u",
        .enable         = sun4u_irq_enable,
        .disable        = sun4u_irq_disable,
-       .end            = sun4u_irq_end,
-       .set_affinity   = sun4u_set_affinity,
-};
-
-static struct irq_chip sun4u_irq_ack = {
-       .typename       = "sun4u+ack",
-       .enable         = sun4u_irq_enable,
-       .disable        = sun4u_irq_disable,
-       .ack            = run_pre_handler,
-       .end            = sun4u_irq_end,
+       .eoi            = sun4u_irq_eoi,
        .set_affinity   = sun4u_set_affinity,
 };
 
@@ -532,7 +510,7 @@ static struct irq_chip sun4v_irq = {
        .typename       = "sun4v",
        .enable         = sun4v_irq_enable,
        .disable        = sun4v_irq_disable,
-       .end            = sun4v_irq_end,
+       .eoi            = sun4v_irq_eoi,
        .set_affinity   = sun4v_set_affinity,
 };
 
@@ -540,31 +518,33 @@ static struct irq_chip sun4v_virq = {
        .typename       = "vsun4v",
        .enable         = sun4v_virq_enable,
        .disable        = sun4v_virq_disable,
-       .end            = sun4v_virq_end,
+       .eoi            = sun4v_virq_eoi,
        .set_affinity   = sun4v_virt_set_affinity,
 };
 
+static void fastcall pre_flow_handler(unsigned int virt_irq,
+                                     struct irq_desc *desc)
+{
+       struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+       unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+
+       data->pre_handler(ino, data->arg1, data->arg2);
+
+       handle_fasteoi_irq(virt_irq, desc);
+}
+
 void irq_install_pre_handler(int virt_irq,
                             void (*func)(unsigned int, void *, void *),
                             void *arg1, void *arg2)
 {
        struct irq_handler_data *data = get_irq_chip_data(virt_irq);
-       struct irq_chip *chip = get_irq_chip(virt_irq);
-
-       if (WARN_ON(chip == &sun4v_irq || chip == &sun4v_virq)) {
-               printk(KERN_ERR "IRQ: Trying to install pre-handler on "
-                      "sun4v irq %u\n", virt_irq);
-               return;
-       }
+       struct irq_desc *desc = irq_desc + virt_irq;
 
        data->pre_handler = func;
-       data->pre_handler_arg1 = arg1;
-       data->pre_handler_arg2 = arg2;
-
-       if (chip == &sun4u_irq_ack)
-               return;
+       data->arg1 = arg1;
+       data->arg2 = arg2;
 
-       set_irq_chip(virt_irq, &sun4u_irq_ack);
+       desc->handle_irq = pre_flow_handler;
 }
 
 unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
@@ -582,7 +562,10 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
        if (!virt_irq) {
                virt_irq = virt_irq_alloc(0, ino);
                bucket_set_virt_irq(__pa(bucket), virt_irq);
-               set_irq_chip(virt_irq, &sun4u_irq);
+               set_irq_chip_and_handler_name(virt_irq,
+                                             &sun4u_irq,
+                                             handle_fasteoi_irq,
+                                             "IVEC");
        }
 
        data = get_irq_chip_data(virt_irq);
@@ -617,7 +600,9 @@ static unsigned int sun4v_build_common(unsigned long sysino,
        if (!virt_irq) {
                virt_irq = virt_irq_alloc(0, sysino);
                bucket_set_virt_irq(__pa(bucket), virt_irq);
-               set_irq_chip(virt_irq, chip);
+               set_irq_chip_and_handler_name(virt_irq, chip,
+                                             handle_fasteoi_irq,
+                                             "IVEC");
        }
 
        data = get_irq_chip_data(virt_irq);
@@ -665,7 +650,10 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
 
        virt_irq = virt_irq_alloc(devhandle, devino);
        bucket_set_virt_irq(__pa(bucket), virt_irq);
-       set_irq_chip(virt_irq, &sun4v_virq);
+
+       set_irq_chip_and_handler_name(virt_irq, &sun4v_virq,
+                                     handle_fasteoi_irq,
+                                     "IVEC");
 
        data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
        if (unlikely(!data))
@@ -724,6 +712,7 @@ void handler_irq(int irq, struct pt_regs *regs)
                             : "memory");
 
        while (bucket_pa) {
+               struct irq_desc *desc;
                unsigned long next_pa;
                unsigned int virt_irq;
 
@@ -731,7 +720,9 @@ void handler_irq(int irq, struct pt_regs *regs)
                virt_irq = bucket_get_virt_irq(bucket_pa);
                bucket_clear_chain_pa(bucket_pa);
 
-               __do_IRQ(virt_irq);
+               desc = irq_desc + virt_irq;
+
+               desc->handle_irq(virt_irq, desc);
 
                bucket_pa = next_pa;
        }
index 85a2be0..c8313cb 100644 (file)
@@ -2057,7 +2057,7 @@ static void fill_cookies(struct cookie_state *sp, unsigned long pa,
 
 static int sg_count_one(struct scatterlist *sg)
 {
-       unsigned long base = page_to_pfn(sg->page) << PAGE_SHIFT;
+       unsigned long base = page_to_pfn(sg_page(sg)) << PAGE_SHIFT;
        long len = sg->length;
 
        if ((sg->offset | len) & (8UL - 1))
index 9b80864..63b3ebc 100644 (file)
@@ -207,8 +207,7 @@ static struct {
        { "SUNW,sun4v-pci", sun4v_pci_init },
        { "pciex108e,80f0", fire_pci_init },
 };
-#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
-                                 sizeof(pci_controller_table[0]))
+#define PCI_NUM_CONTROLLER_TYPES       ARRAY_SIZE(pci_controller_table)
 
 static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp)
 {
index 31a165f..d6d64b4 100644 (file)
@@ -28,8 +28,15 @@ static irqreturn_t sparc64_msiq_interrupt(int irq, void *cookie)
                unsigned long msi;
 
                err = ops->dequeue_msi(pbm, msiqid, &head, &msi);
-               if (likely(err > 0))
-                       __do_IRQ(pbm->msi_irq_table[msi - pbm->msi_first]);
+               if (likely(err > 0)) {
+                       struct irq_desc *desc;
+                       unsigned int virt_irq;
+
+                       virt_irq = pbm->msi_irq_table[msi - pbm->msi_first];
+                       desc = irq_desc + virt_irq;
+
+                       desc->handle_irq(virt_irq, desc);
+               }
 
                if (unlikely(err < 0))
                        goto err_dequeue;
@@ -128,7 +135,8 @@ int sparc64_setup_msi_irq(unsigned int *virt_irq_p,
        if (!*virt_irq_p)
                goto out_err;
 
-       set_irq_chip(*virt_irq_p, &msi_irq);
+       set_irq_chip_and_handler_name(*virt_irq_p, &msi_irq,
+                                     handle_simple_irq, "MSI");
 
        err = alloc_msi(pbm);
        if (unlikely(err < 0))
index fe46ace..8c4875b 100644 (file)
@@ -365,8 +365,7 @@ static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr,
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-#define SG_ENT_PHYS_ADDRESS(SG)        \
-       (__pa(page_address((SG)->page)) + (SG)->offset)
+#define SG_ENT_PHYS_ADDRESS(SG)        (__pa(sg_virt((SG))))
 
 static long fill_sg(long entry, struct device *dev,
                    struct scatterlist *sg,
@@ -477,9 +476,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
        /* Fast path single entry scatterlists. */
        if (nelems == 1) {
                sglist->dma_address =
-                       dma_4v_map_single(dev,
-                                         (page_address(sglist->page) +
-                                          sglist->offset),
+                       dma_4v_map_single(dev, sg_virt(sglist),
                                          sglist->length, direction);
                if (unlikely(sglist->dma_address == DMA_ERROR_CODE))
                        return 0;
index a0b06fd..cc5cb9b 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-y    := math.o
 
-EXTRA_CFLAGS = -I. -Iinclude/math-emu -w
+EXTRA_CFLAGS = -Iinclude/math-emu -w
index 25b248a..3a8cd3d 100644 (file)
@@ -1115,7 +1115,7 @@ static void do_ubd_request(struct request_queue *q)
                        }
                        prepare_request(req, io_req,
                                        (unsigned long long) req->sector << 9,
-                                       sg->offset, sg->length, sg->page);
+                                       sg->offset, sg->length, sg_page(sg));
 
                        last_sectors = sg->length >> 9;
                        n = os_write_file(thread_fd, &io_req,
index f35ea22..a0ae2e7 100644 (file)
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/boot.h>
+#include <asm/asm-offsets.h>
 
 .section ".text.head","ax",@progbits
        .globl startup_32
 
 startup_32:
-       cld
-       cli
+       /* check to see if KEEP_SEGMENTS flag is meaningful */
+       cmpw $0x207, BP_version(%esi)
+       jb 1f
+
+       /* test KEEP_SEGMENTS flag to see if the bootloader is asking
+        * us to not reload segments */
+       testb $(1<<6), BP_loadflags(%esi)
+       jnz 2f
+
+1:     cli
        movl $(__BOOT_DS),%eax
        movl %eax,%ds
        movl %eax,%es
@@ -41,6 +50,8 @@ startup_32:
        movl %eax,%gs
        movl %eax,%ss
 
+2:     cld
+
 /* Calculate the delta between where we were compiled to run
  * at and where we were actually loaded at.  This can only be done
  * with a short local call on x86.  Nothing  else will tell us what
index 1dc1e19..b74d60d 100644 (file)
@@ -247,6 +247,9 @@ static void putstr(const char *s)
        int x,y,pos;
        char c;
 
+       if (RM_SCREEN_INFO.orig_video_mode == 0 && lines == 0 && cols == 0)
+               return;
+
        x = RM_SCREEN_INFO.orig_x;
        y = RM_SCREEN_INFO.orig_y;
 
index f3140e5..8353c81 100644 (file)
@@ -119,7 +119,7 @@ _start:
        # Part 2 of the header, from the old setup.S
 
                .ascii  "HdrS"          # header signature
-               .word   0x0206          # header version number (>= 0x0105)
+               .word   0x0207          # header version number (>= 0x0105)
                                        # or else old loadlin-1.5 will fail)
                .globl realmode_swtch
 realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
@@ -214,6 +214,11 @@ cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
                                                 #added with boot protocol
                                                 #version 2.06
 
+hardware_subarch:      .long 0                 # subarchitecture, added with 2.07
+                                               # default to 0 for normal x86 PC
+
+hardware_subarch_data: .quad 0
+
 # End of setup header #####################################################
 
        .section ".inittext", "ax"
index f1b7cdd..0e45981 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/fixmap.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
+#include <asm/bootparam.h>
 #include <asm/elf.h>
 
 #include <xen/interface/xen.h>
@@ -135,6 +136,7 @@ void foo(void)
 #ifdef CONFIG_LGUEST_GUEST
        BLANK();
        OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
+       OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir);
        OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc);
        OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc);
        OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3);
@@ -146,4 +148,10 @@ void foo(void)
        OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode);
        OFFSET(LGUEST_PAGES_regs, lguest_pages, regs);
 #endif
+
+       BLANK();
+       OFFSET(BP_scratch, boot_params, scratch);
+       OFFSET(BP_loadflags, boot_params, hdr.loadflags);
+       OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
+       OFFSET(BP_version, boot_params, hdr.version);
 }
index 58fd54e..18f500d 100644 (file)
@@ -51,6 +51,13 @@ struct resource code_resource = {
        .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
 };
 
+struct resource bss_resource = {
+       .name   = "Kernel bss",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
 static struct resource system_rom_resource = {
        .name   = "System ROM",
        .start  = 0xf0000,
@@ -254,7 +261,9 @@ static void __init probe_roms(void)
  * and also for regions reported as reserved by the e820.
  */
 static void __init
-legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource)
+legacy_init_iomem_resources(struct resource *code_resource,
+                           struct resource *data_resource,
+                           struct resource *bss_resource)
 {
        int i;
 
@@ -287,6 +296,7 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat
                         */
                        request_resource(res, code_resource);
                        request_resource(res, data_resource);
+                       request_resource(res, bss_resource);
 #ifdef CONFIG_KEXEC
                        if (crashk_res.start != crashk_res.end)
                                request_resource(res, &crashk_res);
@@ -307,9 +317,11 @@ static int __init request_standard_resources(void)
 
        printk("Setting up standard PCI resources\n");
        if (efi_enabled)
-               efi_initialize_iomem_resources(&code_resource, &data_resource);
+               efi_initialize_iomem_resources(&code_resource,
+                               &data_resource, &bss_resource);
        else
-               legacy_init_iomem_resources(&code_resource, &data_resource);
+               legacy_init_iomem_resources(&code_resource,
+                               &data_resource, &bss_resource);
 
        /* EFI systems may still have VGA */
        request_resource(&iomem_resource, &video_ram_resource);
index 5761686..04698e0 100644 (file)
@@ -47,7 +47,7 @@ unsigned long end_pfn_map;
  */
 static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT;
 
-extern struct resource code_resource, data_resource;
+extern struct resource code_resource, data_resource, bss_resource;
 
 /* Check for some hardcoded bad areas that early boot is not allowed to touch */ 
 static inline int bad_addr(unsigned long *addrp, unsigned long size)
@@ -225,6 +225,7 @@ void __init e820_reserve_resources(void)
                         */
                        request_resource(res, &code_resource);
                        request_resource(res, &data_resource);
+                       request_resource(res, &bss_resource);
 #ifdef CONFIG_KEXEC
                        if (crashk_res.start != crashk_res.end)
                                request_resource(res, &crashk_res);
@@ -729,3 +730,22 @@ __init void e820_setup_gap(void)
        printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
                pci_mem_start, gapstart, gapsize);
 }
+
+int __init arch_get_ram_range(int slot, u64 *addr, u64 *size)
+{
+       int i;
+
+       if (slot < 0 || slot >= e820.nr_map)
+               return -1;
+       for (i = slot; i < e820.nr_map; i++) {
+               if (e820.map[i].type != E820_RAM)
+                       continue;
+               break;
+       }
+       if (i == e820.nr_map || e820.map[i].addr > (max_pfn << PAGE_SHIFT))
+               return -1;
+       *addr = e820.map[i].addr;
+       *size = min_t(u64, e820.map[i].size + e820.map[i].addr,
+               max_pfn << PAGE_SHIFT) - *addr;
+       return i + 1;
+}
index b42558c..e2be78f 100644 (file)
@@ -603,7 +603,8 @@ void __init efi_enter_virtual_mode(void)
 
 void __init
 efi_initialize_iomem_resources(struct resource *code_resource,
-                              struct resource *data_resource)
+                              struct resource *data_resource,
+                              struct resource *bss_resource)
 {
        struct resource *res;
        efi_memory_desc_t *md;
@@ -675,6 +676,7 @@ efi_initialize_iomem_resources(struct resource *code_resource,
                if (md->type == EFI_CONVENTIONAL_MEMORY) {
                        request_resource(res, code_resource);
                        request_resource(res, data_resource);
+                       request_resource(res, bss_resource);
 #ifdef CONFIG_KEXEC
                        request_resource(res, &crashk_res);
 #endif
index 3967796..00b1c2c 100644 (file)
@@ -79,22 +79,30 @@ INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_
  */
 .section .text.head,"ax",@progbits
 ENTRY(startup_32)
+       /* check to see if KEEP_SEGMENTS flag is meaningful */
+       cmpw $0x207, BP_version(%esi)
+       jb 1f
+
+       /* test KEEP_SEGMENTS flag to see if the bootloader is asking
+               us to not reload segments */
+       testb $(1<<6), BP_loadflags(%esi)
+       jnz 2f
 
 /*
  * Set segments to known values.
  */
-       cld
-       lgdt boot_gdt_descr - __PAGE_OFFSET
+1:     lgdt boot_gdt_descr - __PAGE_OFFSET
        movl $(__BOOT_DS),%eax
        movl %eax,%ds
        movl %eax,%es
        movl %eax,%fs
        movl %eax,%gs
+2:
 
 /*
  * Clear BSS first so that there are no surprises...
- * No need to cld as DF is already clear from cld above...
  */
+       cld
        xorl %eax,%eax
        movl $__bss_start - __PAGE_OFFSET,%edi
        movl $__bss_stop - __PAGE_OFFSET,%ecx
@@ -128,6 +136,35 @@ ENTRY(startup_32)
        movsl
 1:
 
+#ifdef CONFIG_PARAVIRT
+       cmpw $0x207, (boot_params + BP_version - __PAGE_OFFSET)
+       jb default_entry
+
+       /* Paravirt-compatible boot parameters.  Look to see what architecture
+               we're booting under. */
+       movl (boot_params + BP_hardware_subarch - __PAGE_OFFSET), %eax
+       cmpl $num_subarch_entries, %eax
+       jae bad_subarch
+
+       movl subarch_entries - __PAGE_OFFSET(,%eax,4), %eax
+       subl $__PAGE_OFFSET, %eax
+       jmp *%eax
+
+bad_subarch:
+WEAK(lguest_entry)
+WEAK(xen_entry)
+       /* Unknown implementation; there's really
+          nothing we can do at this point. */
+       ud2a
+.data
+subarch_entries:
+       .long default_entry             /* normal x86/PC */
+       .long lguest_entry              /* lguest hypervisor */
+       .long xen_entry                 /* Xen hypervisor */
+num_subarch_entries = (. - subarch_entries) / 4
+.previous
+#endif /* CONFIG_PARAVIRT */
+
 /*
  * Initialize page tables.  This creates a PDE and a set of page
  * tables, which are located immediately beyond _end.  The variable
@@ -140,6 +177,7 @@ ENTRY(startup_32)
  */
 page_pde_offset = (__PAGE_OFFSET >> 20);
 
+default_entry:
        movl $(pg0 - __PAGE_OFFSET), %edi
        movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
        movl $0x007, %eax                       /* 0x007 = PRESENT+RW+USER */
index b3c2d26..953328b 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/sysdev.h>
 #include <linux/msi.h>
 #include <linux/htirq.h>
+#include <linux/dmar.h>
 #ifdef CONFIG_ACPI
 #include <acpi/acpi_bus.h>
 #endif
@@ -2031,8 +2032,64 @@ void arch_teardown_msi_irq(unsigned int irq)
        destroy_irq(irq);
 }
 
-#endif /* CONFIG_PCI_MSI */
+#ifdef CONFIG_DMAR
+#ifdef CONFIG_SMP
+static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
+{
+       struct irq_cfg *cfg = irq_cfg + irq;
+       struct msi_msg msg;
+       unsigned int dest;
+       cpumask_t tmp;
+
+       cpus_and(tmp, mask, cpu_online_map);
+       if (cpus_empty(tmp))
+               return;
+
+       if (assign_irq_vector(irq, mask))
+               return;
+
+       cpus_and(tmp, cfg->domain, mask);
+       dest = cpu_mask_to_apicid(tmp);
+
+       dmar_msi_read(irq, &msg);
+
+       msg.data &= ~MSI_DATA_VECTOR_MASK;
+       msg.data |= MSI_DATA_VECTOR(cfg->vector);
+       msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+       msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+       dmar_msi_write(irq, &msg);
+       irq_desc[irq].affinity = mask;
+}
+#endif /* CONFIG_SMP */
+
+struct irq_chip dmar_msi_type = {
+       .name = "DMAR_MSI",
+       .unmask = dmar_msi_unmask,
+       .mask = dmar_msi_mask,
+       .ack = ack_apic_edge,
+#ifdef CONFIG_SMP
+       .set_affinity = dmar_msi_set_affinity,
+#endif
+       .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_dmar_msi(unsigned int irq)
+{
+       int ret;
+       struct msi_msg msg;
+
+       ret = msi_compose_msg(NULL, irq, &msg);
+       if (ret < 0)
+               return ret;
+       dmar_msi_write(irq, &msg);
+       set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
+               "edge");
+       return 0;
+}
+#endif
 
+#endif /* CONFIG_PCI_MSI */
 /*
  * Hypertransport interrupt support
  */
index 5098f58..1a20fe3 100644 (file)
@@ -411,8 +411,10 @@ static int calgary_nontranslate_map_sg(struct device* dev,
        int i;
 
        for_each_sg(sg, s, nelems, i) {
-               BUG_ON(!s->page);
-               s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
+               struct page *p = sg_page(s);
+
+               BUG_ON(!p);
+               s->dma_address = virt_to_bus(sg_virt(s));
                s->dma_length = s->length;
        }
        return nelems;
@@ -432,9 +434,9 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
                return calgary_nontranslate_map_sg(dev, sg, nelems, direction);
 
        for_each_sg(sg, s, nelems, i) {
-               BUG_ON(!s->page);
+               BUG_ON(!sg_page(s));
 
-               vaddr = (unsigned long)page_address(s->page) + s->offset;
+               vaddr = (unsigned long) sg_virt(s);
                npages = num_dma_pages(vaddr, s->length);
 
                entry = iommu_range_alloc(tbl, npages);
index afaf9f1..393e272 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/dmar.h>
 #include <asm/io.h>
 #include <asm/iommu.h>
 #include <asm/calgary.h>
@@ -305,6 +306,8 @@ void __init pci_iommu_alloc(void)
        detect_calgary();
 #endif
 
+       detect_intel_iommu();
+
 #ifdef CONFIG_SWIOTLB
        pci_swiotlb_init();
 #endif
@@ -316,6 +319,8 @@ static int __init pci_iommu_init(void)
        calgary_iommu_init();
 #endif
 
+       intel_iommu_init();
+
 #ifdef CONFIG_IOMMU
        gart_iommu_init();
 #endif
index 5cdfab6..c56e9ee 100644 (file)
@@ -302,7 +302,7 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,
 #endif
 
        for_each_sg(sg, s, nents, i) {
-               unsigned long addr = page_to_phys(s->page) + s->offset; 
+               unsigned long addr = sg_phys(s);
                if (nonforced_iommu(dev, addr, s->length)) { 
                        addr = dma_map_area(dev, addr, s->length, dir);
                        if (addr == bad_dma_address) { 
@@ -397,7 +397,7 @@ static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        start_sg = sgmap = sg;
        ps = NULL; /* shut up gcc */
        for_each_sg(sg, s, nents, i) {
-               dma_addr_t addr = page_to_phys(s->page) + s->offset;
+               dma_addr_t addr = sg_phys(s);
                s->dma_address = addr;
                BUG_ON(s->length == 0); 
 
index e85d436..faf70bd 100644 (file)
@@ -62,8 +62,8 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
        int i;
 
        for_each_sg(sg, s, nents, i) {
-               BUG_ON(!s->page);
-               s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
+               BUG_ON(!sg_page(s));
+               s->dma_address = virt_to_bus(sg_virt(s));
                if (!check_addr("map_sg", hwdev, s->dma_address, s->length))
                        return 0;
                s->dma_length = s->length;
index ba2e165..cc0e914 100644 (file)
@@ -60,6 +60,7 @@
 #include <asm/vmi.h>
 #include <setup_arch.h>
 #include <bios_ebda.h>
+#include <asm/cacheflush.h>
 
 /* This value is set up by the early boot code to point to the value
    immediately after the boot time page tables.  It contains a *physical*
@@ -73,6 +74,7 @@ int disable_pse __devinitdata = 0;
  */
 extern struct resource code_resource;
 extern struct resource data_resource;
+extern struct resource bss_resource;
 
 /* cpu data as detected by the assembly code in head.S */
 struct cpuinfo_x86 new_cpu_data __cpuinitdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
@@ -600,6 +602,8 @@ void __init setup_arch(char **cmdline_p)
        code_resource.end = virt_to_phys(_etext)-1;
        data_resource.start = virt_to_phys(_etext);
        data_resource.end = virt_to_phys(_edata)-1;
+       bss_resource.start = virt_to_phys(&__bss_start);
+       bss_resource.end = virt_to_phys(&__bss_stop)-1;
 
        parse_early_param();
 
index 31322d4..e7a9e36 100644 (file)
@@ -58,6 +58,7 @@
 #include <asm/numa.h>
 #include <asm/sections.h>
 #include <asm/dmi.h>
+#include <asm/cacheflush.h>
 
 /*
  * Machine setup..
@@ -133,6 +134,12 @@ struct resource code_resource = {
        .end = 0,
        .flags = IORESOURCE_RAM,
 };
+struct resource bss_resource = {
+       .name = "Kernel bss",
+       .start = 0,
+       .end = 0,
+       .flags = IORESOURCE_RAM,
+};
 
 #ifdef CONFIG_PROC_VMCORE
 /* elfcorehdr= specifies the location of elf core header
@@ -276,6 +283,8 @@ void __init setup_arch(char **cmdline_p)
        code_resource.end = virt_to_phys(&_etext)-1;
        data_resource.start = virt_to_phys(&_etext);
        data_resource.end = virt_to_phys(&_edata)-1;
+       bss_resource.start = virt_to_phys(&__bss_start);
+       bss_resource.end = virt_to_phys(&__bss_stop)-1;
 
        early_identify_cpu(&boot_cpu_data);
 
diff --git a/arch/x86/lguest/Kconfig b/arch/x86/lguest/Kconfig
new file mode 100644 (file)
index 0000000..c4dffbe
--- /dev/null
@@ -0,0 +1,14 @@
+config LGUEST_GUEST
+       bool "Lguest guest support"
+       select PARAVIRT
+       depends on !X86_PAE
+       select VIRTIO
+       select VIRTIO_RING
+       select VIRTIO_CONSOLE
+       help
+         Lguest is a tiny in-kernel hypervisor.  Selecting this will
+         allow your kernel to boot under lguest.  This option will increase
+         your kernel size by about 6k.  If in doubt, say N.
+
+         If you say Y here, make sure you say Y (or M) to the virtio block
+         and net drivers which lguest needs.
diff --git a/arch/x86/lguest/Makefile b/arch/x86/lguest/Makefile
new file mode 100644 (file)
index 0000000..27f0c9e
--- /dev/null
@@ -0,0 +1 @@
+obj-y          := i386_head.o boot.o
similarity index 93%
rename from drivers/lguest/lguest.c
rename to arch/x86/lguest/boot.c
index 3ba337d..d2235db 100644 (file)
@@ -55,7 +55,7 @@
 #include <linux/clockchips.h>
 #include <linux/lguest.h>
 #include <linux/lguest_launcher.h>
-#include <linux/lguest_bus.h>
+#include <linux/virtio_console.h>
 #include <asm/paravirt.h>
 #include <asm/param.h>
 #include <asm/page.h>
@@ -65,6 +65,7 @@
 #include <asm/e820.h>
 #include <asm/mce.h>
 #include <asm/io.h>
+#include <asm/i387.h>
 
 /*G:010 Welcome to the Guest!
  *
@@ -85,9 +86,10 @@ struct lguest_data lguest_data = {
        .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
        .noirq_start = (u32)lguest_noirq_start,
        .noirq_end = (u32)lguest_noirq_end,
+       .kernel_address = PAGE_OFFSET,
        .blocked_interrupts = { 1 }, /* Block timer interrupts */
+       .syscall_vec = SYSCALL_VECTOR,
 };
-struct lguest_device_desc *lguest_devices;
 static cycle_t clock_base;
 
 /*G:035 Notice the lazy_hcall() above, rather than hcall().  This is our first
@@ -146,10 +148,10 @@ void async_hcall(unsigned long call,
                /* Table full, so do normal hcall which will flush table. */
                hcall(call, arg1, arg2, arg3);
        } else {
-               lguest_data.hcalls[next_call].eax = call;
-               lguest_data.hcalls[next_call].edx = arg1;
-               lguest_data.hcalls[next_call].ebx = arg2;
-               lguest_data.hcalls[next_call].ecx = arg3;
+               lguest_data.hcalls[next_call].arg0 = call;
+               lguest_data.hcalls[next_call].arg1 = arg1;
+               lguest_data.hcalls[next_call].arg2 = arg2;
+               lguest_data.hcalls[next_call].arg3 = arg3;
                /* Arguments must all be written before we mark it to go */
                wmb();
                lguest_data.hcall_status[next_call] = 0;
@@ -160,46 +162,6 @@ void async_hcall(unsigned long call,
 }
 /*:*/
 
-/* Wrappers for the SEND_DMA and BIND_DMA hypercalls.  This is mainly because
- * Jeff Garzik complained that __pa() should never appear in drivers, and this
- * helps remove most of them.   But also, it wraps some ugliness. */
-void lguest_send_dma(unsigned long key, struct lguest_dma *dma)
-{
-       /* The hcall might not write this if something goes wrong */
-       dma->used_len = 0;
-       hcall(LHCALL_SEND_DMA, key, __pa(dma), 0);
-}
-
-int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas,
-                   unsigned int num, u8 irq)
-{
-       /* This is the only hypercall which actually wants 5 arguments, and we
-        * only support 4.  Fortunately the interrupt number is always less
-        * than 256, so we can pack it with the number of dmas in the final
-        * argument.  */
-       if (!hcall(LHCALL_BIND_DMA, key, __pa(dmas), (num << 8) | irq))
-               return -ENOMEM;
-       return 0;
-}
-
-/* Unbinding is the same hypercall as binding, but with 0 num & irq. */
-void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas)
-{
-       hcall(LHCALL_BIND_DMA, key, __pa(dmas), 0);
-}
-
-/* For guests, device memory can be used as normal memory, so we cast away the
- * __iomem to quieten sparse. */
-void *lguest_map(unsigned long phys_addr, unsigned long pages)
-{
-       return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
-}
-
-void lguest_unmap(void *addr)
-{
-       iounmap((__force void __iomem *)addr);
-}
-
 /*G:033
  * Here are our first native-instruction replacements: four functions for
  * interrupt control.
@@ -680,6 +642,7 @@ static struct clocksource lguest_clock = {
        .mask           = CLOCKSOURCE_MASK(64),
        .mult           = 1 << 22,
        .shift          = 22,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 /* The "scheduler clock" is just our real clock, adjusted to start at zero */
@@ -761,11 +724,9 @@ static void lguest_time_init(void)
         * the TSC, otherwise it's a dumb nanosecond-resolution clock.  Either
         * way, the "rating" is initialized so high that it's always chosen
         * over any other clocksource. */
-       if (lguest_data.tsc_khz) {
+       if (lguest_data.tsc_khz)
                lguest_clock.mult = clocksource_khz2mult(lguest_data.tsc_khz,
                                                         lguest_clock.shift);
-               lguest_clock.flags = CLOCK_SOURCE_IS_CONTINUOUS;
-       }
        clock_base = lguest_clock_read();
        clocksource_register(&lguest_clock);
 
@@ -889,6 +850,23 @@ static __init char *lguest_memory_setup(void)
        return "LGUEST";
 }
 
+/* Before virtqueues are set up, we use LHCALL_NOTIFY on normal memory to
+ * produce console output. */
+static __init int early_put_chars(u32 vtermno, const char *buf, int count)
+{
+       char scratch[17];
+       unsigned int len = count;
+
+       if (len > sizeof(scratch) - 1)
+               len = sizeof(scratch) - 1;
+       scratch[len] = '\0';
+       memcpy(scratch, buf, len);
+       hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0);
+
+       /* This routine returns the number of bytes actually written. */
+       return len;
+}
+
 /*G:050
  * Patching (Powerfully Placating Performance Pedants)
  *
@@ -950,18 +928,8 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
 /*G:030 Once we get to lguest_init(), we know we're a Guest.  The pv_ops
  * structures in the kernel provide points for (almost) every routine we have
  * to override to avoid privileged instructions. */
-__init void lguest_init(void *boot)
+__init void lguest_init(void)
 {
-       /* Copy boot parameters first: the Launcher put the physical location
-        * in %esi, and head.S converted that to a virtual address and handed
-        * it to us.  We use "__memcpy" because "memcpy" sometimes tries to do
-        * tricky things to go faster, and we're not ready for that. */
-       __memcpy(&boot_params, boot, PARAM_SIZE);
-       /* The boot parameters also tell us where the command-line is: save
-        * that, too. */
-       __memcpy(boot_command_line, __va(boot_params.hdr.cmd_line_ptr),
-              COMMAND_LINE_SIZE);
-
        /* We're under lguest, paravirt is enabled, and we're running at
         * privilege level 1, not 0 as normal. */
        pv_info.name = "lguest";
@@ -1033,11 +1001,7 @@ __init void lguest_init(void *boot)
 
        /*G:070 Now we've seen all the paravirt_ops, we return to
         * lguest_init() where the rest of the fairly chaotic boot setup
-        * occurs.
-        *
-        * The Host expects our first hypercall to tell it where our "struct
-        * lguest_data" is, so we do that first. */
-       hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
+        * occurs. */
 
        /* The native boot code sets up initial page tables immediately after
         * the kernel itself, and sets init_pg_tables_end so they're not
@@ -1050,11 +1014,6 @@ __init void lguest_init(void *boot)
         * the normal data segment to get through booting. */
        asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory");
 
-       /* Clear the part of the kernel data which is expected to be zero.
-        * Normally it will be anyway, but if we're loading from a bzImage with
-        * CONFIG_RELOCATALE=y, the relocations will be sitting here. */
-       memset(__bss_start, 0, __bss_stop - __bss_start);
-
        /* The Host uses the top of the Guest's virtual address space for the
         * Host<->Guest Switcher, and it tells us how much it needs in
         * lguest_data.reserve_mem, set up on the LGUEST_INIT hypercall. */
@@ -1092,6 +1051,9 @@ __init void lguest_init(void *boot)
         * adapted for lguest's use. */
        add_preferred_console("hvc", 0, NULL);
 
+       /* Register our very early console. */
+       virtio_cons_early_init(early_put_chars);
+
        /* Last of all, we set the power management poweroff hook to point to
         * the Guest routine to power off. */
        pm_power_off = lguest_power_off;
similarity index 73%
rename from drivers/lguest/lguest_asm.S
rename to arch/x86/lguest/i386_head.S
index 1ddcd5c..ebc6ac7 100644 (file)
@@ -1,25 +1,47 @@
 #include <linux/linkage.h>
 #include <linux/lguest.h>
+#include <asm/lguest_hcall.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 #include <asm/processor-flags.h>
 
-/*G:020 This is where we begin: we have a magic signature which the launcher
- * looks for.  The plan is that the Linux boot protocol will be extended with a
- * "platform type" field which will guide us here from the normal entry point,
- * but for the moment this suffices.  The normal boot code uses %esi for the
- * boot header, so we do too.  We convert it to a virtual address by adding
- * PAGE_OFFSET, and hand it to lguest_init() as its argument (ie. %eax).
+/*G:020 This is where we begin: head.S notes that the boot header's platform
+ * type field is "1" (lguest), so calls us here.  The boot header is in %esi.
+ *
+ * WARNING: be very careful here!  We're running at addresses equal to physical
+ * addesses (around 0), not above PAGE_OFFSET as most code expectes
+ * (eg. 0xC0000000).  Jumps are relative, so they're OK, but we can't touch any
+ * data.
  *
  * The .section line puts this code in .init.text so it will be discarded after
  * boot. */
 .section .init.text, "ax", @progbits
-.ascii "GenuineLguest"
-       /* Set up initial stack. */
-       movl $(init_thread_union+THREAD_SIZE),%esp
-       movl %esi, %eax
-       addl $__PAGE_OFFSET, %eax
-       jmp lguest_init
+ENTRY(lguest_entry)
+       /* Make initial hypercall now, so we can set up the pagetables. */
+       movl $LHCALL_LGUEST_INIT, %eax
+       movl $lguest_data - __PAGE_OFFSET, %edx
+       int $LGUEST_TRAP_ENTRY
+
+       /* The Host put the toplevel pagetable in lguest_data.pgdir.  The movsl
+        * instruction uses %esi implicitly. */
+       movl lguest_data - __PAGE_OFFSET + LGUEST_DATA_pgdir, %esi
+
+       /* Copy first 32 entries of page directory to __PAGE_OFFSET entries.
+        * This means the first 128M of kernel memory will be mapped at
+        * PAGE_OFFSET where the kernel expects to run.  This will get it far
+        * enough through boot to switch to its own pagetables. */
+       movl $32, %ecx
+       movl %esi, %edi
+       addl $((__PAGE_OFFSET >> 22) * 4), %edi
+       rep
+       movsl
+
+       /* Set up the initial stack so we can run C code. */
+       movl $(init_thread_union+THREAD_SIZE),%esp
+
+       /* Jumps are relative, and we're running __PAGE_OFFSET too low at the
+        * moment. */
+       jmp lguest_init+__PAGE_OFFSET
 
 /*G:055 We create a macro which puts the assembler code between lgstart_ and
  * lgend_ markers.  These templates are put in the .text section: they can't be
index c7b7dfe..c40afba 100644 (file)
@@ -61,10 +61,10 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot,
        return base;
 } 
 
-static void cache_flush_page(void *adr)
+void clflush_cache_range(void *adr, int size)
 {
        int i;
-       for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
+       for (i = 0; i < size; i += boot_cpu_data.x86_clflush_size)
                clflush(adr+i);
 }
 
@@ -80,7 +80,7 @@ static void flush_kernel_map(void *arg)
                asm volatile("wbinvd" ::: "memory");
        else list_for_each_entry(pg, l, lru) {
                void *adr = page_address(pg);
-               cache_flush_page(adr);
+               clflush_cache_range(adr, PAGE_SIZE);
        }
        __flush_tlb_all();
 }
index 9df99e1..fbfa55c 100644 (file)
@@ -3,8 +3,9 @@
 #
 
 config XEN
-       bool "Enable support for Xen hypervisor"
-       depends on PARAVIRT && X86_CMPXCHG && X86_TSC && !NEED_MULTIPLE_NODES
+       bool "Xen guest support"
+       select PARAVIRT
+       depends on X86_CMPXCHG && X86_TSC && !NEED_MULTIPLE_NODES && !(X86_VISWS || X86_VOYAGER)
        help
          This is the Linux Xen port.  Enabling this will allow the
          kernel to boot in a paravirtualized environment under the
index aab25f3..c2d2499 100644 (file)
@@ -750,6 +750,38 @@ config PCI_DOMAINS
        depends on PCI
        default y
 
+config DMAR
+       bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
+       depends on PCI_MSI && ACPI && EXPERIMENTAL
+       default y
+       help
+         DMA remapping (DMAR) devices support enables independent address
+         translations for Direct Memory Access (DMA) from devices.
+         These DMA remapping devices are reported via ACPI tables
+         and include PCI device scope covered by these DMA
+         remapping devices.
+
+config DMAR_GFX_WA
+       bool "Support for Graphics workaround"
+       depends on DMAR
+       default y
+       help
+        Current Graphics drivers tend to use physical address
+        for DMA and avoid using DMA APIs. Setting this config
+        option permits the IOMMU driver to set a unity map for
+        all the OS-visible memory. Hence the driver can continue
+        to use physical addresses for DMA.
+
+config DMAR_FLOPPY_WA
+       bool
+       depends on DMAR
+       default y
+       help
+        Floppy disk drivers are know to bypass DMA API calls
+        thereby failing to work when IOMMU is enabled. This
+        workaround will setup a 1:1 mapping for the first
+        16M to make floppy (an ISA device) work.
+
 source "drivers/pci/pcie/Kconfig"
 
 source "drivers/pci/Kconfig"
index 9c5185f..40aa55b 100644 (file)
@@ -8,7 +8,8 @@
 #
 
 
-EXTRA_CFLAGS   += -fno-builtin -Iarch/$(ARCH)/boot/include
+# KBUILD_CFLAGS used when building rest of boot (takes effect recursively)
+KBUILD_CFLAGS  += -fno-builtin -Iarch/$(ARCH)/boot/include
 HOSTFLAGS      += -Iarch/$(ARCH)/boot/include
 
 BIG_ENDIAN     := $(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#")
index 8025d64..de5ba47 100644 (file)
@@ -1351,11 +1351,22 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
 new_segment:
                        if (!sg)
                                sg = sglist;
-                       else
+                       else {
+                               /*
+                                * If the driver previously mapped a shorter
+                                * list, we could see a termination bit
+                                * prematurely unless it fully inits the sg
+                                * table on each mapping. We KNOW that there
+                                * must be more entries here or the driver
+                                * would be buggy, so force clear the
+                                * termination bit to avoid doing a full
+                                * sg_init_table() in drivers for each command.
+                                */
+                               sg->page_link &= ~0x02;
                                sg = sg_next(sg);
+                       }
 
-                       memset(sg, 0, sizeof(*sg));
-                       sg->page = bvec->bv_page;
+                       sg_set_page(sg, bvec->bv_page);
                        sg->length = nbytes;
                        sg->offset = bvec->bv_offset;
                        nsegs++;
@@ -1363,6 +1374,9 @@ new_segment:
                bvprv = bvec;
        } /* segments in rq */
 
+       if (sg)
+               __sg_mark_end(sg);
+
        return nsegs;
 }
 
index e56de67..8871dec 100644 (file)
@@ -41,7 +41,7 @@ static int update2(struct hash_desc *desc,
                return 0;
 
        for (;;) {
-               struct page *pg = sg->page;
+               struct page *pg = sg_page(sg);
                unsigned int offset = sg->offset;
                unsigned int l = sg->length;
 
index 8802fb6..e4eb6ac 100644 (file)
@@ -159,7 +159,8 @@ static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
        desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
 
        sg_set_buf(sg1, ipad, bs);
-       sg1[1].page = (void *)sg;
+
+       sg_set_page(&sg[1], (void *) sg);
        sg1[1].length = 0;
        sg_set_buf(sg2, opad, bs + ds);
 
index d6852c3..b9bbda0 100644 (file)
@@ -54,7 +54,7 @@ static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
        if (out) {
                struct page *page;
 
-               page = walk->sg->page + ((walk->offset - 1) >> PAGE_SHIFT);
+               page = sg_page(walk->sg) + ((walk->offset - 1) >> PAGE_SHIFT);
                flush_dcache_page(page);
        }
 
index 9c73e37..87ed681 100644 (file)
 
 static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
 {
-       return (++sg)->length ? sg : (void *)sg->page;
+       return (++sg)->length ? sg : (void *) sg_page(sg);
 }
 
 static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in,
                                                struct scatter_walk *walk_out)
 {
-       return !(((walk_in->sg->page - walk_out->sg->page) << PAGE_SHIFT) +
+       return !(((sg_page(walk_in->sg) - sg_page(walk_out->sg)) << PAGE_SHIFT) +
                 (int)(walk_in->offset - walk_out->offset));
 }
 
@@ -60,7 +60,7 @@ static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk,
 
 static inline struct page *scatterwalk_page(struct scatter_walk *walk)
 {
-       return walk->sg->page + (walk->offset >> PAGE_SHIFT);
+       return sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT);
 }
 
 static inline void scatterwalk_unmap(void *vaddr, int out)
index 18d489c..d741c63 100644 (file)
@@ -317,7 +317,7 @@ static void test_cipher(char *algo, int enc,
                                goto out;
                        }
 
-                       q = kmap(sg[0].page) + sg[0].offset;
+                       q = kmap(sg_page(&sg[0])) + sg[0].offset;
                        hexdump(q, cipher_tv[i].rlen);
 
                        printk("%s\n",
@@ -390,7 +390,7 @@ static void test_cipher(char *algo, int enc,
                        temp = 0;
                        for (k = 0; k < cipher_tv[i].np; k++) {
                                printk("page %u\n", k);
-                               q = kmap(sg[k].page) + sg[k].offset;
+                               q = kmap(sg_page(&sg[k])) + sg[k].offset;
                                hexdump(q, cipher_tv[i].tap[k]);
                                printk("%s\n",
                                        memcmp(q, cipher_tv[i].result + temp,
index 9f502b8..ac68f3b 100644 (file)
@@ -120,7 +120,7 @@ static int crypto_xcbc_digest_update2(struct hash_desc *pdesc,
 
        do {
 
-               struct page *pg = sg[i].page;
+               struct page *pg = sg_page(&sg[i]);
                unsigned int offset = sg[i].offset;
                unsigned int slen = sg[i].length;
 
index 34f40ea..f4076d9 100644 (file)
@@ -94,5 +94,5 @@ source "drivers/kvm/Kconfig"
 
 source "drivers/uio/Kconfig"
 
-source "drivers/lguest/Kconfig"
+source "drivers/virtio/Kconfig"
 endmenu
index cfe38ff..560496b 100644 (file)
@@ -91,3 +91,4 @@ obj-$(CONFIG_HID)             += hid/
 obj-$(CONFIG_PPC_PS3)          += ps3/
 obj-$(CONFIG_OF)               += of/
 obj-$(CONFIG_SSB)              += ssb/
+obj-$(CONFIG_VIRTIO)           += virtio/
index 629eadb..69092bc 100644 (file)
@@ -4296,7 +4296,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
                sg_last(sg, qc->orig_n_elem)->length += qc->pad_len;
                if (pad_buf) {
                        struct scatterlist *psg = &qc->pad_sgent;
-                       void *addr = kmap_atomic(psg->page, KM_IRQ0);
+                       void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
                        memcpy(addr + psg->offset, pad_buf, qc->pad_len);
                        kunmap_atomic(addr, KM_IRQ0);
                }
@@ -4686,11 +4686,11 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
                 * data in this function or read data in ata_sg_clean.
                 */
                offset = lsg->offset + lsg->length - qc->pad_len;
-               psg->page = nth_page(lsg->page, offset >> PAGE_SHIFT);
+               sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT));
                psg->offset = offset_in_page(offset);
 
                if (qc->tf.flags & ATA_TFLAG_WRITE) {
-                       void *addr = kmap_atomic(psg->page, KM_IRQ0);
+                       void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
                        memcpy(pad_buf, addr + psg->offset, qc->pad_len);
                        kunmap_atomic(addr, KM_IRQ0);
                }
@@ -4836,7 +4836,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
        if (qc->curbytes == qc->nbytes - qc->sect_size)
                ap->hsm_task_state = HSM_ST_LAST;
 
-       page = qc->cursg->page;
+       page = sg_page(qc->cursg);
        offset = qc->cursg->offset + qc->cursg_ofs;
 
        /* get the current page and offset */
@@ -4988,7 +4988,7 @@ next_sg:
 
        sg = qc->cursg;
 
-       page = sg->page;
+       page = sg_page(sg);
        offset = sg->offset + qc->cursg_ofs;
 
        /* get the current page and offset */
index 9fbb39c..5b758b9 100644 (file)
@@ -1544,7 +1544,7 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
        struct scatterlist *sg = scsi_sglist(cmd);
 
        if (sg) {
-               buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+               buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
                buflen = sg->length;
        } else {
                buf = NULL;
index c41d072..7868707 100644 (file)
@@ -137,7 +137,7 @@ static ssize_t show_mem_state(struct sys_device *dev, char *buf)
        return len;
 }
 
-static inline int memory_notify(unsigned long val, void *v)
+int memory_notify(unsigned long val, void *v)
 {
        return blocking_notifier_call_chain(&memory_chain, val, v);
 }
@@ -183,7 +183,6 @@ memory_block_action(struct memory_block *mem, unsigned long action)
                        break;
                case MEM_OFFLINE:
                        mem->state = MEM_GOING_OFFLINE;
-                       memory_notify(MEM_GOING_OFFLINE, NULL);
                        start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
                        ret = remove_memory(start_paddr,
                                            PAGES_PER_SECTION << PAGE_SHIFT);
@@ -191,7 +190,6 @@ memory_block_action(struct memory_block *mem, unsigned long action)
                                mem->state = old_state;
                                break;
                        }
-                       memory_notify(MEM_MAPPING_INVALID, NULL);
                        break;
                default:
                        printk(KERN_WARNING "%s(%p, %ld) unknown action: %ld\n",
@@ -199,11 +197,6 @@ memory_block_action(struct memory_block *mem, unsigned long action)
                        WARN_ON(1);
                        ret = -EINVAL;
        }
-       /*
-        * For now, only notify on successful memory operations
-        */
-       if (!ret)
-               memory_notify(action, NULL);
 
        return ret;
 }
index 84d6aa5..9030c37 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/init.h>
 #include <linux/jiffies.h>
 #include <linux/random.h>
+#include <linux/scatterlist.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include "DAC960.h"
@@ -345,6 +346,7 @@ static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
        Command->V1.ScatterGatherList =
                (DAC960_V1_ScatterGatherSegment_T *)ScatterGatherCPU;
        Command->V1.ScatterGatherListDMA = ScatterGatherDMA;
+       sg_init_table(Command->cmd_sglist, DAC960_V1_ScatterGatherLimit);
       } else {
         Command->cmd_sglist = Command->V2.ScatterList;
        Command->V2.ScatterGatherList =
@@ -353,6 +355,7 @@ static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
        Command->V2.RequestSense =
                                (DAC960_SCSI_RequestSense_T *)RequestSenseCPU;
        Command->V2.RequestSenseDMA = RequestSenseDMA;
+       sg_init_table(Command->cmd_sglist, DAC960_V2_ScatterGatherLimit);
       }
     }
   return true;
index ce4b1e4..4d0119e 100644 (file)
@@ -425,4 +425,10 @@ config XEN_BLKDEV_FRONTEND
          block device driver.  It communicates with a back-end driver
          in another domain which drives the actual block device.
 
+config VIRTIO_BLK
+       tristate "Virtio block driver (EXPERIMENTAL)"
+       depends on EXPERIMENTAL && VIRTIO
+       ---help---
+         This is the virtual block driver for lguest.  Say Y or M.
+
 endif # BLK_DEV
index 014e721..7691505 100644 (file)
@@ -25,10 +25,10 @@ obj-$(CONFIG_SUNVDC)                += sunvdc.o
 obj-$(CONFIG_BLK_DEV_UMEM)     += umem.o
 obj-$(CONFIG_BLK_DEV_NBD)      += nbd.o
 obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o
+obj-$(CONFIG_VIRTIO_BLK)       += virtio_blk.o
 
 obj-$(CONFIG_VIODASD)          += viodasd.o
 obj-$(CONFIG_BLK_DEV_SX8)      += sx8.o
 obj-$(CONFIG_BLK_DEV_UB)       += ub.o
 
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += xen-blkfront.o
-obj-$(CONFIG_LGUEST_BLOCK)     += lguest_blk.o
index 7c2cfde..5a6fe17 100644 (file)
@@ -2610,7 +2610,7 @@ static void do_cciss_request(struct request_queue *q)
               (int)creq->nr_sectors);
 #endif                         /* CCISS_DEBUG */
 
-       memset(tmp_sg, 0, sizeof(tmp_sg));
+       sg_init_table(tmp_sg, MAXSGENTRIES);
        seg = blk_rq_map_sg(q, creq, tmp_sg);
 
        /* get the DMA records for the setup */
@@ -2621,7 +2621,7 @@ static void do_cciss_request(struct request_queue *q)
 
        for (i = 0; i < seg; i++) {
                c->SG[i].Len = tmp_sg[i].length;
-               temp64.val = (__u64) pci_map_page(h->pdev, tmp_sg[i].page,
+               temp64.val = (__u64) pci_map_page(h->pdev, sg_page(&tmp_sg[i]),
                                                  tmp_sg[i].offset,
                                                  tmp_sg[i].length, dir);
                c->SG[i].Addr.lower = temp64.val32.lower;
index 568603d..c8132d9 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/spinlock.h>
 #include <linux/blkdev.h>
 #include <linux/genhd.h>
+#include <linux/scatterlist.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -918,6 +919,7 @@ queue_next:
 DBGPX(
        printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors);
 );
+       sg_init_table(tmp_sg, SG_MAX);
        seg = blk_rq_map_sg(q, creq, tmp_sg);
 
        /* Now do all the DMA Mappings */
@@ -929,7 +931,7 @@ DBGPX(
        {
                c->req.sg[i].size = tmp_sg[i].length;
                c->req.sg[i].addr = (__u32) pci_map_page(h->pci_dev,
-                                                tmp_sg[i].page,
+                                                sg_page(&tmp_sg[i]),
                                                 tmp_sg[i].offset,
                                                 tmp_sg[i].length, dir);
        }
index 4053503..1b58b01 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/crypto.h>
 #include <linux/blkdev.h>
 #include <linux/loop.h>
+#include <linux/scatterlist.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
 
@@ -119,14 +120,17 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
                .tfm = tfm,
                .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
        };
-       struct scatterlist sg_out = { NULL, };
-       struct scatterlist sg_in = { NULL, };
+       struct scatterlist sg_out;
+       struct scatterlist sg_in;
 
        encdec_cbc_t encdecfunc;
        struct page *in_page, *out_page;
        unsigned in_offs, out_offs;
        int err;
 
+       sg_init_table(&sg_out, 1);
+       sg_init_table(&sg_in, 1);
+
        if (cmd == READ) {
                in_page = raw_page;
                in_offs = raw_off;
@@ -146,11 +150,11 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
                u32 iv[4] = { 0, };
                iv[0] = cpu_to_le32(IV & 0xffffffff);
 
-               sg_in.page = in_page;
+               sg_set_page(&sg_in, in_page);
                sg_in.offset = in_offs;
                sg_in.length = sz;
 
-               sg_out.page = out_page;
+               sg_set_page(&sg_out, out_page);
                sg_out.offset = out_offs;
                sg_out.length = sz;
 
diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c
deleted file mode 100644 (file)
index fa8e423..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-/*D:400
- * The Guest block driver
- *
- * This is a simple block driver, which appears as /dev/lgba, lgbb, lgbc etc.
- * The mechanism is simple: we place the information about the request in the
- * device page, then use SEND_DMA (containing the data for a write, or an empty
- * "ping" DMA for a read).
- :*/
-/* Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-//#define DEBUG
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/lguest_bus.h>
-
-static char next_block_index = 'a';
-
-/*D:420 Here is the structure which holds all the information we need about
- * each Guest block device.
- *
- * I'm sure at this stage, you're wondering "hey, where was the adventure I was
- * promised?" and thinking "Rusty sucks, I shall say nasty things about him on
- * my blog".  I think Real adventures have boring bits, too, and you're in the
- * middle of one.  But it gets better.  Just not quite yet. */
-struct blockdev
-{
-       /* The block queue infrastructure wants a spinlock: it is held while it
-        * calls our block request function.  We grab it in our interrupt
-        * handler so the responses don't mess with new requests. */
-       spinlock_t lock;
-
-       /* The disk structure registered with kernel. */
-       struct gendisk *disk;
-
-       /* The major device number for this disk, and the interrupt.  We only
-        * really keep them here for completeness; we'd need them if we
-        * supported device unplugging. */
-       int major;
-       int irq;
-
-       /* The physical address of this device's memory page */
-       unsigned long phys_addr;
-       /* The mapped memory page for convenient acces. */
-       struct lguest_block_page *lb_page;
-
-       /* We only have a single request outstanding at a time: this is it. */
-       struct lguest_dma dma;
-       struct request *req;
-};
-
-/*D:495 We originally used end_request() throughout the driver, but it turns
- * out that end_request() is deprecated, and doesn't actually end the request
- * (which seems like a good reason to deprecate it!).  It simply ends the first
- * bio.  So if we had 3 bios in a "struct request" we would do all 3,
- * end_request(), do 2, end_request(), do 1 and end_request(): twice as much
- * work as we needed to do.
- *
- * This reinforced to me that I do not understand the block layer.
- *
- * Nonetheless, Jens Axboe gave me this nice helper to end all chunks of a
- * request.  This improved disk speed by 130%. */
-static void end_entire_request(struct request *req, int uptodate)
-{
-       if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
-               BUG();
-       add_disk_randomness(req->rq_disk);
-       blkdev_dequeue_request(req);
-       end_that_request_last(req, uptodate);
-}
-
-/* I'm told there are only two stories in the world worth telling: love and
- * hate.  So there used to be a love scene here like this:
- *
- *  Launcher:  We could make beautiful I/O together, you and I.
- *  Guest:     My, that's a big disk!
- *
- * Unfortunately, it was just too raunchy for our otherwise-gentle tale. */
-
-/*D:490 This is the interrupt handler, called when a block read or write has
- * been completed for us. */
-static irqreturn_t lgb_irq(int irq, void *_bd)
-{
-       /* We handed our "struct blockdev" as the argument to request_irq(), so
-        * it is passed through to us here.  This tells us which device we're
-        * dealing with in case we have more than one. */
-       struct blockdev *bd = _bd;
-       unsigned long flags;
-
-       /* We weren't doing anything?  Strange, but could happen if we shared
-        * interrupts (we don't!). */
-       if (!bd->req) {
-               pr_debug("No work!\n");
-               return IRQ_NONE;
-       }
-
-       /* Not done yet?  That's equally strange. */
-       if (!bd->lb_page->result) {
-               pr_debug("No result!\n");
-               return IRQ_NONE;
-       }
-
-       /* We have to grab the lock before ending the request. */
-       spin_lock_irqsave(&bd->lock, flags);
-       /* "result" is 1 for success, 2 for failure: end_entire_request() wants
-        * to know whether this succeeded or not. */
-       end_entire_request(bd->req, bd->lb_page->result == 1);
-       /* Clear out request, it's done. */
-       bd->req = NULL;
-       /* Reset incoming DMA for next time. */
-       bd->dma.used_len = 0;
-       /* Ready for more reads or writes */
-       blk_start_queue(bd->disk->queue);
-       spin_unlock_irqrestore(&bd->lock, flags);
-
-       /* The interrupt was for us, we dealt with it. */
-       return IRQ_HANDLED;
-}
-
-/*D:480 The block layer's "struct request" contains a number of "struct bio"s,
- * each of which contains "struct bio_vec"s, each of which contains a page, an
- * offset and a length.
- *
- * Fortunately there are iterators to help us walk through the "struct
- * request".  Even more fortunately, there were plenty of places to steal the
- * code from.  We pack the "struct request" into our "struct lguest_dma" and
- * return the total length. */
-static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma)
-{
-       unsigned int i = 0, len = 0;
-       struct req_iterator iter;
-       struct bio_vec *bvec;
-
-       rq_for_each_segment(bvec, req, iter) {
-               /* We told the block layer not to give us too many. */
-               BUG_ON(i == LGUEST_MAX_DMA_SECTIONS);
-               /* If we had a zero-length segment, it would look like
-                * the end of the data referred to by the "struct
-                * lguest_dma", so make sure that doesn't happen. */
-               BUG_ON(!bvec->bv_len);
-               /* Convert page & offset to a physical address */
-               dma->addr[i] = page_to_phys(bvec->bv_page)
-                       + bvec->bv_offset;
-               dma->len[i] = bvec->bv_len;
-               len += bvec->bv_len;
-               i++;
-       }
-       /* If the array isn't full, we mark the end with a 0 length */
-       if (i < LGUEST_MAX_DMA_SECTIONS)
-               dma->len[i] = 0;
-       return len;
-}
-
-/* This creates an empty DMA, useful for prodding the Host without sending data
- * (ie. when we want to do a read) */
-static void empty_dma(struct lguest_dma *dma)
-{
-       dma->len[0] = 0;
-}
-
-/*D:470 Setting up a request is fairly easy: */
-static void setup_req(struct blockdev *bd,
-                     int type, struct request *req, struct lguest_dma *dma)
-{
-       /* The type is 1 (write) or 0 (read). */
-       bd->lb_page->type = type;
-       /* The sector on disk where the read or write starts. */
-       bd->lb_page->sector = req->sector;
-       /* The result is initialized to 0 (unfinished). */
-       bd->lb_page->result = 0;
-       /* The current request (so we can end it in the interrupt handler). */
-       bd->req = req;
-       /* The number of bytes: returned as a side-effect of req_to_dma(),
-        * which packs the block layer's "struct request" into our "struct
-        * lguest_dma" */
-       bd->lb_page->bytes = req_to_dma(req, dma);
-}
-
-/*D:450 Write is pretty straightforward: we pack the request into a "struct
- * lguest_dma", then use SEND_DMA to send the request. */
-static void do_write(struct blockdev *bd, struct request *req)
-{
-       struct lguest_dma send;
-
-       pr_debug("lgb: WRITE sector %li\n", (long)req->sector);
-       setup_req(bd, 1, req, &send);
-
-       lguest_send_dma(bd->phys_addr, &send);
-}
-
-/* Read is similar to write, except we pack the request into our receive
- * "struct lguest_dma" and send through an empty DMA just to tell the Host that
- * there's a request pending. */
-static void do_read(struct blockdev *bd, struct request *req)
-{
-       struct lguest_dma ping;
-
-       pr_debug("lgb: READ sector %li\n", (long)req->sector);
-       setup_req(bd, 0, req, &bd->dma);
-
-       empty_dma(&ping);
-       lguest_send_dma(bd->phys_addr, &ping);
-}
-
-/*D:440 This where requests come in: we get handed the request queue and are
- * expected to pull a "struct request" off it until we've finished them or
- * we're waiting for a reply: */
-static void do_lgb_request(struct request_queue *q)
-{
-       struct blockdev *bd;
-       struct request *req;
-
-again:
-       /* This sometimes returns NULL even on the very first time around.  I
-        * wonder if it's something to do with letting elves handle the request
-        * queue... */
-       req = elv_next_request(q);
-       if (!req)
-               return;
-
-       /* We attached the struct blockdev to the disk: get it back */
-       bd = req->rq_disk->private_data;
-       /* Sometimes we get repeated requests after blk_stop_queue(), but we
-        * can only handle one at a time. */
-       if (bd->req)
-               return;
-
-       /* We only do reads and writes: no tricky business! */
-       if (!blk_fs_request(req)) {
-               pr_debug("Got non-command 0x%08x\n", req->cmd_type);
-               req->errors++;
-               end_entire_request(req, 0);
-               goto again;
-       }
-
-       if (rq_data_dir(req) == WRITE)
-               do_write(bd, req);
-       else
-               do_read(bd, req);
-
-       /* We've put out the request, so stop any more coming in until we get
-        * an interrupt, which takes us to lgb_irq() to re-enable the queue. */
-       blk_stop_queue(q);
-}
-
-/*D:430 This is the "struct block_device_operations" we attach to the disk at
- * the end of lguestblk_probe().  It doesn't seem to want much. */
-static struct block_device_operations lguestblk_fops = {
-       .owner = THIS_MODULE,
-};
-
-/*D:425 Setting up a disk device seems to involve a lot of code.  I'm not sure
- * quite why.  I do know that the IDE code sent two or three of the maintainers
- * insane, perhaps this is the fringe of the same disease?
- *
- * As in the console code, the probe function gets handed the generic
- * lguest_device from lguest_bus.c: */
-static int lguestblk_probe(struct lguest_device *lgdev)
-{
-       struct blockdev *bd;
-       int err;
-       int irqflags = IRQF_SHARED;
-
-       /* First we allocate our own "struct blockdev" and initialize the easy
-        * fields. */
-       bd = kmalloc(sizeof(*bd), GFP_KERNEL);
-       if (!bd)
-               return -ENOMEM;
-
-       spin_lock_init(&bd->lock);
-       bd->irq = lgdev_irq(lgdev);
-       bd->req = NULL;
-       bd->dma.used_len = 0;
-       bd->dma.len[0] = 0;
-       /* The descriptor in the lguest_devices array provided by the Host
-        * gives the Guest the physical page number of the device's page. */
-       bd->phys_addr = (lguest_devices[lgdev->index].pfn << PAGE_SHIFT);
-
-       /* We use lguest_map() to get a pointer to the device page */
-       bd->lb_page = lguest_map(bd->phys_addr, 1);
-       if (!bd->lb_page) {
-               err = -ENOMEM;
-               goto out_free_bd;
-       }
-
-       /* We need a major device number: 0 means "assign one dynamically". */
-       bd->major = register_blkdev(0, "lguestblk");
-       if (bd->major < 0) {
-               err = bd->major;
-               goto out_unmap;
-       }
-
-       /* This allocates a "struct gendisk" where we pack all the information
-        * about the disk which the rest of Linux sees.  The argument is the
-        * number of minor devices desired: we need one minor for the main
-        * disk, and one for each partition.  Of course, we can't possibly know
-        * how many partitions are on the disk (add_disk does that).
-        */
-       bd->disk = alloc_disk(16);
-       if (!bd->disk) {
-               err = -ENOMEM;
-               goto out_unregister_blkdev;
-       }
-
-       /* Every disk needs a queue for requests to come in: we set up the
-        * queue with a callback function (the core of our driver) and the lock
-        * to use. */
-       bd->disk->queue = blk_init_queue(do_lgb_request, &bd->lock);
-       if (!bd->disk->queue) {
-               err = -ENOMEM;
-               goto out_put_disk;
-       }
-
-       /* We can only handle a certain number of pointers in our SEND_DMA
-        * call, so we set that with blk_queue_max_hw_segments().  This is not
-        * to be confused with blk_queue_max_phys_segments() of course!  I
-        * know, who could possibly confuse the two?
-        *
-        * Well, it's simple to tell them apart: this one seems to work and the
-        * other one didn't. */
-       blk_queue_max_hw_segments(bd->disk->queue, LGUEST_MAX_DMA_SECTIONS);
-
-       /* Due to technical limitations of our Host (and simple coding) we
-        * can't have a single buffer which crosses a page boundary.  Tell it
-        * here.  This means that our maximum request size is 16
-        * (LGUEST_MAX_DMA_SECTIONS) pages. */
-       blk_queue_segment_boundary(bd->disk->queue, PAGE_SIZE-1);
-
-       /* We name our disk: this becomes the device name when udev does its
-        * magic thing and creates the device node, such as /dev/lgba.
-        * next_block_index is a global which starts at 'a'.  Unfortunately
-        * this simple increment logic means that the 27th disk will be called
-        * "/dev/lgb{".  In that case, I recommend having at least 29 disks, so
-        * your /dev directory will be balanced. */
-       sprintf(bd->disk->disk_name, "lgb%c", next_block_index++);
-
-       /* We look to the device descriptor again to see if this device's
-        * interrupts are expected to be random.  If they are, we tell the irq
-        * subsystem.  At the moment this bit is always set. */
-       if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
-               irqflags |= IRQF_SAMPLE_RANDOM;
-
-       /* Now we have the name and irqflags, we can request the interrupt; we
-        * give it the "struct blockdev" we have set up to pass to lgb_irq()
-        * when there is an interrupt. */
-       err = request_irq(bd->irq, lgb_irq, irqflags, bd->disk->disk_name, bd);
-       if (err)
-               goto out_cleanup_queue;
-
-       /* We bind our one-entry DMA pool to the key for this block device so
-        * the Host can reply to our requests.  The key is equal to the
-        * physical address of the device's page, which is conveniently
-        * unique. */
-       err = lguest_bind_dma(bd->phys_addr, &bd->dma, 1, bd->irq);
-       if (err)
-               goto out_free_irq;
-
-       /* We finish our disk initialization and add the disk to the system. */
-       bd->disk->major = bd->major;
-       bd->disk->first_minor = 0;
-       bd->disk->private_data = bd;
-       bd->disk->fops = &lguestblk_fops;
-       /* This is initialized to the disk size by the Launcher. */
-       set_capacity(bd->disk, bd->lb_page->num_sectors);
-       add_disk(bd->disk);
-
-       printk(KERN_INFO "%s: device %i at major %d\n",
-              bd->disk->disk_name, lgdev->index, bd->major);
-
-       /* We don't need to keep the "struct blockdev" around, but if we ever
-        * implemented device removal, we'd need this. */
-       lgdev->private = bd;
-       return 0;
-
-out_free_irq:
-       free_irq(bd->irq, bd);
-out_cleanup_queue:
-       blk_cleanup_queue(bd->disk->queue);
-out_put_disk:
-       put_disk(bd->disk);
-out_unregister_blkdev:
-       unregister_blkdev(bd->major, "lguestblk");
-out_unmap:
-       lguest_unmap(bd->lb_page);
-out_free_bd:
-       kfree(bd);
-       return err;
-}
-
-/*D:410 The boilerplate code for registering the lguest block driver is just
- * like the console: */
-static struct lguest_driver lguestblk_drv = {
-       .name = "lguestblk",
-       .owner = THIS_MODULE,
-       .device_type = LGUEST_DEVICE_T_BLOCK,
-       .probe = lguestblk_probe,
-};
-
-static __init int lguestblk_init(void)
-{
-       return register_lguest_driver(&lguestblk_drv);
-}
-module_init(lguestblk_init);
-
-MODULE_DESCRIPTION("Lguest block driver");
-MODULE_LICENSE("GPL");
index 317a790..7276f7d 100644 (file)
@@ -388,6 +388,7 @@ static int __send_request(struct request *req)
                op = VD_OP_BWRITE;
        }
 
+       sg_init_table(sg, port->ring_cookies);
        nsg = blk_rq_map_sg(req->q, req, sg);
 
        len = 0;
index 402209f..52dc5e1 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/hdreg.h>
 #include <linux/dma-mapping.h>
 #include <linux/completion.h>
+#include <linux/scatterlist.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -522,6 +523,7 @@ static struct carm_request *carm_get_request(struct carm_host *host)
                        host->n_msgs++;
 
                        assert(host->n_msgs <= CARM_MAX_REQ);
+                       sg_init_table(crq->sg, CARM_MAX_REQ_SG);
                        return crq;
                }
 
index c57dd2b..14143f2 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/usb_usual.h>
 #include <linux/blkdev.h>
 #include <linux/timer.h>
+#include <linux/scatterlist.h>
 #include <scsi/scsi.h>
 
 #define DRV_NAME "ub"
@@ -656,6 +657,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
        if ((cmd = ub_get_cmd(lun)) == NULL)
                return -1;
        memset(cmd, 0, sizeof(struct ub_scsi_cmd));
+       sg_init_table(cmd->sgv, UB_MAX_REQ_SG);
 
        blkdev_dequeue_request(rq);
 
@@ -1309,9 +1311,8 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        else
                pipe = sc->send_bulk_pipe;
        sc->last_pipe = pipe;
-       usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
-           page_address(sg->page) + sg->offset, sg->length,
-           ub_urb_complete, sc);
+       usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg),
+           sg->length, ub_urb_complete, sc);
        sc->work_urb.actual_length = 0;
        sc->work_urb.error_count = 0;
        sc->work_urb.status = 0;
@@ -1427,7 +1428,7 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        scmd->state = UB_CMDST_INIT;
        scmd->nsg = 1;
        sg = &scmd->sgv[0];
-       sg->page = virt_to_page(sc->top_sense);
+       sg_set_page(sg, virt_to_page(sc->top_sense));
        sg->offset = (unsigned long)sc->top_sense & (PAGE_SIZE-1);
        sg->length = UB_SENSE_SIZE;
        scmd->len = UB_SENSE_SIZE;
@@ -1863,7 +1864,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
        cmd->state = UB_CMDST_INIT;
        cmd->nsg = 1;
        sg = &cmd->sgv[0];
-       sg->page = virt_to_page(p);
+       sg_set_page(sg, virt_to_page(p));
        sg->offset = (unsigned long)p & (PAGE_SIZE-1);
        sg->length = 8;
        cmd->len = 8;
index e824b67..ab5d404 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/completion.h>
 #include <linux/device.h>
+#include <linux/scatterlist.h>
 
 #include <asm/uaccess.h>
 #include <asm/vio.h>
@@ -270,6 +271,7 @@ static int send_request(struct request *req)
         d = req->rq_disk->private_data;
 
        /* Now build the scatter-gather list */
+       sg_init_table(sg, VIOMAXBLOCKDMA);
        nsg = blk_rq_map_sg(req->q, req, sg);
        nsg = dma_map_sg(d->dev, sg, nsg, direction);
 
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
new file mode 100644 (file)
index 0000000..a901eee
--- /dev/null
@@ -0,0 +1,308 @@
+//#define DEBUG
+#include <linux/spinlock.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/virtio.h>
+#include <linux/virtio_blk.h>
+#include <linux/virtio_blk.h>
+
+static unsigned char virtblk_index = 'a';
+struct virtio_blk
+{
+       spinlock_t lock;
+
+       struct virtio_device *vdev;
+       struct virtqueue *vq;
+
+       /* The disk structure for the kernel. */
+       struct gendisk *disk;
+
+       /* Request tracking. */
+       struct list_head reqs;
+
+       mempool_t *pool;
+
+       /* Scatterlist: can be too big for stack. */
+       struct scatterlist sg[3+MAX_PHYS_SEGMENTS];
+};
+
+struct virtblk_req
+{
+       struct list_head list;
+       struct request *req;
+       struct virtio_blk_outhdr out_hdr;
+       struct virtio_blk_inhdr in_hdr;
+};
+
+static bool blk_done(struct virtqueue *vq)
+{
+       struct virtio_blk *vblk = vq->vdev->priv;
+       struct virtblk_req *vbr;
+       unsigned int len;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vblk->lock, flags);
+       while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
+               int uptodate;
+               switch (vbr->in_hdr.status) {
+               case VIRTIO_BLK_S_OK:
+                       uptodate = 1;
+                       break;
+               case VIRTIO_BLK_S_UNSUPP:
+                       uptodate = -ENOTTY;
+                       break;
+               default:
+                       uptodate = 0;
+                       break;
+               }
+
+               end_dequeued_request(vbr->req, uptodate);
+               list_del(&vbr->list);
+               mempool_free(vbr, vblk->pool);
+       }
+       /* In case queue is stopped waiting for more buffers. */
+       blk_start_queue(vblk->disk->queue);
+       spin_unlock_irqrestore(&vblk->lock, flags);
+       return true;
+}
+
+static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
+                  struct request *req)
+{
+       unsigned long num, out, in;
+       struct virtblk_req *vbr;
+
+       vbr = mempool_alloc(vblk->pool, GFP_ATOMIC);
+       if (!vbr)
+               /* When another request finishes we'll try again. */
+               return false;
+
+       vbr->req = req;
+       if (blk_fs_request(vbr->req)) {
+               vbr->out_hdr.type = 0;
+               vbr->out_hdr.sector = vbr->req->sector;
+               vbr->out_hdr.ioprio = vbr->req->ioprio;
+       } else if (blk_pc_request(vbr->req)) {
+               vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
+               vbr->out_hdr.sector = 0;
+               vbr->out_hdr.ioprio = vbr->req->ioprio;
+       } else {
+               /* We don't put anything else in the queue. */
+               BUG();
+       }
+
+       if (blk_barrier_rq(vbr->req))
+               vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;
+
+       /* We have to zero this, otherwise blk_rq_map_sg gets upset. */
+       memset(vblk->sg, 0, sizeof(vblk->sg));
+       sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
+       num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
+       sg_set_buf(&vblk->sg[num+1], &vbr->in_hdr, sizeof(vbr->in_hdr));
+
+       if (rq_data_dir(vbr->req) == WRITE) {
+               vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
+               out = 1 + num;
+               in = 1;
+       } else {
+               vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
+               out = 1;
+               in = 1 + num;
+       }
+
+       if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) {
+               mempool_free(vbr, vblk->pool);
+               return false;
+       }
+
+       list_add_tail(&vbr->list, &vblk->reqs);
+       return true;
+}
+
+static void do_virtblk_request(struct request_queue *q)
+{
+       struct virtio_blk *vblk = NULL;
+       struct request *req;
+       unsigned int issued = 0;
+
+       while ((req = elv_next_request(q)) != NULL) {
+               vblk = req->rq_disk->private_data;
+               BUG_ON(req->nr_phys_segments > ARRAY_SIZE(vblk->sg));
+
+               /* If this request fails, stop queue and wait for something to
+                  finish to restart it. */
+               if (!do_req(q, vblk, req)) {
+                       blk_stop_queue(q);
+                       break;
+               }
+               blkdev_dequeue_request(req);
+               issued++;
+       }
+
+       if (issued)
+               vblk->vq->vq_ops->kick(vblk->vq);
+}
+
+static int virtblk_ioctl(struct inode *inode, struct file *filp,
+                        unsigned cmd, unsigned long data)
+{
+       return scsi_cmd_ioctl(filp, inode->i_bdev->bd_disk->queue,
+                             inode->i_bdev->bd_disk, cmd,
+                             (void __user *)data);
+}
+
+static struct block_device_operations virtblk_fops = {
+       .ioctl = virtblk_ioctl,
+       .owner = THIS_MODULE,
+};
+
+static int virtblk_probe(struct virtio_device *vdev)
+{
+       struct virtio_blk *vblk;
+       int err, major;
+       void *token;
+       unsigned int len;
+       u64 cap;
+       u32 v;
+
+       vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
+       if (!vblk) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       INIT_LIST_HEAD(&vblk->reqs);
+       spin_lock_init(&vblk->lock);
+       vblk->vdev = vdev;
+
+       /* We expect one virtqueue, for output. */
+       vblk->vq = vdev->config->find_vq(vdev, blk_done);
+       if (IS_ERR(vblk->vq)) {
+               err = PTR_ERR(vblk->vq);
+               goto out_free_vblk;
+       }
+
+       vblk->pool = mempool_create_kmalloc_pool(1,sizeof(struct virtblk_req));
+       if (!vblk->pool) {
+               err = -ENOMEM;
+               goto out_free_vq;
+       }
+
+       major = register_blkdev(0, "virtblk");
+       if (major < 0) {
+               err = major;
+               goto out_mempool;
+       }
+
+       /* FIXME: How many partitions?  How long is a piece of string? */
+       vblk->disk = alloc_disk(1 << 4);
+       if (!vblk->disk) {
+               err = -ENOMEM;
+               goto out_unregister_blkdev;
+       }
+
+       vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
+       if (!vblk->disk->queue) {
+               err = -ENOMEM;
+               goto out_put_disk;
+       }
+
+       sprintf(vblk->disk->disk_name, "vd%c", virtblk_index++);
+       vblk->disk->major = major;
+       vblk->disk->first_minor = 0;
+       vblk->disk->private_data = vblk;
+       vblk->disk->fops = &virtblk_fops;
+
+       /* If barriers are supported, tell block layer that queue is ordered */
+       token = vdev->config->find(vdev, VIRTIO_CONFIG_BLK_F, &len);
+       if (virtio_use_bit(vdev, token, len, VIRTIO_BLK_F_BARRIER))
+               blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
+
+       err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_CAPACITY, &cap);
+       if (err) {
+               dev_err(&vdev->dev, "Bad/missing capacity in config\n");
+               goto out_put_disk;
+       }
+
+       /* If capacity is too big, truncate with warning. */
+       if ((sector_t)cap != cap) {
+               dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n",
+                        (unsigned long long)cap);
+               cap = (sector_t)-1;
+       }
+       set_capacity(vblk->disk, cap);
+
+       err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SIZE_MAX, &v);
+       if (!err)
+               blk_queue_max_segment_size(vblk->disk->queue, v);
+       else if (err != -ENOENT) {
+               dev_err(&vdev->dev, "Bad SIZE_MAX in config\n");
+               goto out_put_disk;
+       }
+
+       err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SEG_MAX, &v);
+       if (!err)
+               blk_queue_max_hw_segments(vblk->disk->queue, v);
+       else if (err != -ENOENT) {
+               dev_err(&vdev->dev, "Bad SEG_MAX in config\n");
+               goto out_put_disk;
+       }
+
+       add_disk(vblk->disk);
+       return 0;
+
+out_put_disk:
+       put_disk(vblk->disk);
+out_unregister_blkdev:
+       unregister_blkdev(major, "virtblk");
+out_mempool:
+       mempool_destroy(vblk->pool);
+out_free_vq:
+       vdev->config->del_vq(vblk->vq);
+out_free_vblk:
+       kfree(vblk);
+out:
+       return err;
+}
+
+static void virtblk_remove(struct virtio_device *vdev)
+{
+       struct virtio_blk *vblk = vdev->priv;
+       int major = vblk->disk->major;
+
+       BUG_ON(!list_empty(&vblk->reqs));
+       blk_cleanup_queue(vblk->disk->queue);
+       put_disk(vblk->disk);
+       unregister_blkdev(major, "virtblk");
+       mempool_destroy(vblk->pool);
+       kfree(vblk);
+}
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static struct virtio_driver virtio_blk = {
+       .driver.name =  KBUILD_MODNAME,
+       .driver.owner = THIS_MODULE,
+       .id_table =     id_table,
+       .probe =        virtblk_probe,
+       .remove =       __devexit_p(virtblk_remove),
+};
+
+static int __init init(void)
+{
+       return register_virtio_driver(&virtio_blk);
+}
+
+static void __exit fini(void)
+{
+       unregister_virtio_driver(&virtio_blk);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio block driver");
+MODULE_LICENSE("GPL");
index b9fbe6e..075598e 100644 (file)
@@ -22,6 +22,30 @@ config BT_HCIUSB_SCO
 
          Say Y here to compile support for SCO over HCI USB.
 
+config BT_HCIBTUSB
+       tristate "HCI USB driver (alternate version)"
+       depends on USB && EXPERIMENTAL && BT_HCIUSB=n
+       help
+         Bluetooth HCI USB driver.
+         This driver is required if you want to use Bluetooth devices with
+         USB interface.
+
+          This driver is still experimental and has no SCO support.
+
+         Say Y here to compile support for Bluetooth USB devices into the
+         kernel or say M to compile it as module (btusb).
+
+config BT_HCIBTSDIO
+       tristate "HCI SDIO driver"
+       depends on MMC
+       help
+         Bluetooth HCI SDIO driver.
+         This driver is required if you want to use Bluetooth device with
+         SDIO interface.
+
+         Say Y here to compile support for Bluetooth SDIO devices into the
+         kernel or say M to compile it as module (btsdio).
+
 config BT_HCIUART
        tristate "HCI UART driver"
        help
@@ -55,6 +79,17 @@ config BT_HCIUART_BCSP
 
          Say Y here to compile support for HCI BCSP protocol.
 
+config BT_HCIUART_LL
+       bool "HCILL protocol support"
+       depends on BT_HCIUART
+       help
+         HCILL (HCI Low Level) is a serial protocol for communication
+         between Bluetooth device and host. This protocol is required for
+         serial Bluetooth devices that are based on Texas Instruments'
+         BRF chips.
+
+         Say Y here to compile support for HCILL protocol.
+
 config BT_HCIBCM203X
        tristate "HCI BCM203x USB driver"
        depends on USB
index 08c10e1..77444af 100644 (file)
@@ -13,7 +13,11 @@ obj-$(CONFIG_BT_HCIBT3C)     += bt3c_cs.o
 obj-$(CONFIG_BT_HCIBLUECARD)   += bluecard_cs.o
 obj-$(CONFIG_BT_HCIBTUART)     += btuart_cs.o
 
+obj-$(CONFIG_BT_HCIBTUSB)      += btusb.o
+obj-$(CONFIG_BT_HCIBTSDIO)     += btsdio.o
+
 hci_uart-y                             := hci_ldisc.o
 hci_uart-$(CONFIG_BT_HCIUART_H4)       += hci_h4.o
 hci_uart-$(CONFIG_BT_HCIUART_BCSP)     += hci_bcsp.o
+hci_uart-$(CONFIG_BT_HCIUART_LL)       += hci_ll.o
 hci_uart-objs                          := $(hci_uart-y)
index 851de4d..bcf5792 100644 (file)
@@ -503,10 +503,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
        unsigned int iobase;
        unsigned char reg;
 
-       if (!info || !info->hdev) {
-               BT_ERR("Call of irq %d for unknown device", irq);
-               return IRQ_NONE;
-       }
+       BUG_ON(!info->hdev);
 
        if (!test_bit(CARD_READY, &(info->hw_state)))
                return IRQ_HANDLED;
index e8ebd5d..1375b53 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Digianswer Bluetooth USB driver
  *
- *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-#include <linux/module.h>
-
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/sched.h>
 #include <linux/errno.h>
+#include <linux/skbuff.h>
 
 #include <linux/usb.h>
 
@@ -39,7 +40,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "0.8"
+#define VERSION "0.9"
 
 static int ignore = 0;
 
@@ -52,393 +53,285 @@ static struct usb_device_id bpa10x_table[] = {
 
 MODULE_DEVICE_TABLE(usb, bpa10x_table);
 
-#define BPA10X_CMD_EP          0x00
-#define BPA10X_EVT_EP          0x81
-#define BPA10X_TX_EP           0x02
-#define BPA10X_RX_EP           0x82
-
-#define BPA10X_CMD_BUF_SIZE    252
-#define BPA10X_EVT_BUF_SIZE    16
-#define BPA10X_TX_BUF_SIZE     384
-#define BPA10X_RX_BUF_SIZE     384
-
 struct bpa10x_data {
-       struct hci_dev          *hdev;
-       struct usb_device       *udev;
+       struct hci_dev    *hdev;
+       struct usb_device *udev;
 
-       rwlock_t                lock;
+       struct usb_anchor tx_anchor;
+       struct usb_anchor rx_anchor;
 
-       struct sk_buff_head     cmd_queue;
-       struct urb              *cmd_urb;
-       struct urb              *evt_urb;
-       struct sk_buff          *evt_skb;
-       unsigned int            evt_len;
-
-       struct sk_buff_head     tx_queue;
-       struct urb              *tx_urb;
-       struct urb              *rx_urb;
+       struct sk_buff *rx_skb[2];
 };
 
-#define HCI_VENDOR_HDR_SIZE    5
+#define HCI_VENDOR_HDR_SIZE 5
 
 struct hci_vendor_hdr {
-       __u8    type;
-       __le16  snum;
-       __le16  dlen;
+       __u8    type;
+       __le16  snum;
+       __le16  dlen;
 } __attribute__ ((packed));
 
-static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count)
+static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
 {
-       struct hci_acl_hdr *ah;
-       struct hci_sco_hdr *sh;
-       struct hci_vendor_hdr *vh;
-       struct sk_buff *skb;
-       int len;
+       struct bpa10x_data *data = hdev->driver_data;
+
+       BT_DBG("%s queue %d buffer %p count %d", hdev->name,
+                                                       queue, buf, count);
+
+       if (queue < 0 || queue > 1)
+               return -EILSEQ;
+
+       hdev->stat.byte_rx += count;
 
        while (count) {
-               switch (*buf++) {
-               case HCI_ACLDATA_PKT:
-                       ah = (struct hci_acl_hdr *) buf;
-                       len = HCI_ACL_HDR_SIZE + __le16_to_cpu(ah->dlen);
-                       skb = bt_skb_alloc(len, GFP_ATOMIC);
-                       if (skb) {
-                               memcpy(skb_put(skb, len), buf, len);
-                               skb->dev = (void *) data->hdev;
-                               bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-                               hci_recv_frame(skb);
-                       }
-                       break;
+               struct sk_buff *skb = data->rx_skb[queue];
+               struct { __u8 type; int expect; } *scb;
+               int type, len = 0;
 
-               case HCI_SCODATA_PKT:
-                       sh = (struct hci_sco_hdr *) buf;
-                       len = HCI_SCO_HDR_SIZE + sh->dlen;
-                       skb = bt_skb_alloc(len, GFP_ATOMIC);
-                       if (skb) {
-                               memcpy(skb_put(skb, len), buf, len);
-                               skb->dev = (void *) data->hdev;
-                               bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
-                               hci_recv_frame(skb);
+               if (!skb) {
+                       /* Start of the frame */
+
+                       type = *((__u8 *) buf);
+                       count--; buf++;
+
+                       switch (type) {
+                       case HCI_EVENT_PKT:
+                               if (count >= HCI_EVENT_HDR_SIZE) {
+                                       struct hci_event_hdr *h = buf;
+                                       len = HCI_EVENT_HDR_SIZE + h->plen;
+                               } else
+                                       return -EILSEQ;
+                               break;
+
+                       case HCI_ACLDATA_PKT:
+                               if (count >= HCI_ACL_HDR_SIZE) {
+                                       struct hci_acl_hdr *h = buf;
+                                       len = HCI_ACL_HDR_SIZE +
+                                                       __le16_to_cpu(h->dlen);
+                               } else
+                                       return -EILSEQ;
+                               break;
+
+                       case HCI_SCODATA_PKT:
+                               if (count >= HCI_SCO_HDR_SIZE) {
+                                       struct hci_sco_hdr *h = buf;
+                                       len = HCI_SCO_HDR_SIZE + h->dlen;
+                               } else
+                                       return -EILSEQ;
+                               break;
+
+                       case HCI_VENDOR_PKT:
+                               if (count >= HCI_VENDOR_HDR_SIZE) {
+                                       struct hci_vendor_hdr *h = buf;
+                                       len = HCI_VENDOR_HDR_SIZE +
+                                                       __le16_to_cpu(h->dlen);
+                               } else
+                                       return -EILSEQ;
+                               break;
                        }
-                       break;
 
-               case HCI_VENDOR_PKT:
-                       vh = (struct hci_vendor_hdr *) buf;
-                       len = HCI_VENDOR_HDR_SIZE + __le16_to_cpu(vh->dlen);
                        skb = bt_skb_alloc(len, GFP_ATOMIC);
-                       if (skb) {
-                               memcpy(skb_put(skb, len), buf, len);
-                               skb->dev = (void *) data->hdev;
-                               bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
-                               hci_recv_frame(skb);
+                       if (!skb) {
+                               BT_ERR("%s no memory for packet", hdev->name);
+                               return -ENOMEM;
                        }
-                       break;
-
-               default:
-                       len = count - 1;
-                       break;
-               }
 
-               buf   += len;
-               count -= (len + 1);
-       }
-}
-
-static int bpa10x_recv_event(struct bpa10x_data *data, unsigned char *buf, int size)
-{
-       BT_DBG("data %p buf %p size %d", data, buf, size);
+                       skb->dev = (void *) hdev;
 
-       if (data->evt_skb) {
-               struct sk_buff *skb = data->evt_skb;
+                       data->rx_skb[queue] = skb;
 
-               memcpy(skb_put(skb, size), buf, size);
+                       scb = (void *) skb->cb;
+                       scb->type = type;
+                       scb->expect = len;
+               } else {
+                       /* Continuation */
 
-               if (skb->len == data->evt_len) {
-                       data->evt_skb = NULL;
-                       data->evt_len = 0;
-                       hci_recv_frame(skb);
-               }
-       } else {
-               struct sk_buff *skb;
-               struct hci_event_hdr *hdr;
-               unsigned char pkt_type;
-               int pkt_len = 0;
-
-               if (size < HCI_EVENT_HDR_SIZE + 1) {
-                       BT_ERR("%s event packet block with size %d is too short",
-                                                       data->hdev->name, size);
-                       return -EILSEQ;
+                       scb = (void *) skb->cb;
+                       len = scb->expect;
                }
 
-               pkt_type = *buf++;
-               size--;
-
-               if (pkt_type != HCI_EVENT_PKT) {
-                       BT_ERR("%s unexpected event packet start byte 0x%02x",
-                                                       data->hdev->name, pkt_type);
-                       return -EPROTO;
-               }
+               len = min(len, count);
 
-               hdr = (struct hci_event_hdr *) buf;
-               pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
+               memcpy(skb_put(skb, len), buf, len);
 
-               skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
-               if (!skb) {
-                       BT_ERR("%s no memory for new event packet",
-                                                       data->hdev->name);
-                       return -ENOMEM;
-               }
+               scb->expect -= len;
 
-               skb->dev = (void *) data->hdev;
-               bt_cb(skb)->pkt_type = pkt_type;
+               if (scb->expect == 0) {
+                       /* Complete frame */
 
-               memcpy(skb_put(skb, size), buf, size);
+                       data->rx_skb[queue] = NULL;
 
-               if (pkt_len == size) {
+                       bt_cb(skb)->pkt_type = scb->type;
                        hci_recv_frame(skb);
-               } else {
-                       data->evt_skb = skb;
-                       data->evt_len = pkt_len;
                }
+
+               count -= len; buf += len;
        }
 
        return 0;
 }
 
-static void bpa10x_wakeup(struct bpa10x_data *data)
+static void bpa10x_tx_complete(struct urb *urb)
 {
-       struct urb *urb;
-       struct sk_buff *skb;
-       int err;
+       struct sk_buff *skb = urb->context;
+       struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 
-       BT_DBG("data %p", data);
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
 
-       urb = data->cmd_urb;
-       if (urb->status == -EINPROGRESS)
-               skb = NULL;
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               goto done;
+
+       if (!urb->status)
+               hdev->stat.byte_tx += urb->transfer_buffer_length;
        else
-               skb = skb_dequeue(&data->cmd_queue);
+               hdev->stat.err_tx++;
 
-       if (skb) {
-               struct usb_ctrlrequest *cr;
+done:
+       kfree(urb->setup_packet);
 
-               if (skb->len > BPA10X_CMD_BUF_SIZE) {
-                       BT_ERR("%s command packet with size %d is too big",
-                                                       data->hdev->name, skb->len);
-                       kfree_skb(skb);
-                       return;
-               }
+       kfree_skb(skb);
+}
+
+static void bpa10x_rx_complete(struct urb *urb)
+{
+       struct hci_dev *hdev = urb->context;
+       struct bpa10x_data *data = hdev->driver_data;
+       int err;
 
-               cr = (struct usb_ctrlrequest *) urb->setup_packet;
-               cr->wLength = __cpu_to_le16(skb->len);
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
 
-               skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
-               urb->transfer_buffer_length = skb->len;
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return;
 
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err < 0 && err != -ENODEV) {
-                       BT_ERR("%s submit failed for command urb %p with error %d",
-                                                       data->hdev->name, urb, err);
-                       skb_queue_head(&data->cmd_queue, skb);
-               } else
-                       kfree_skb(skb);
+       if (urb->status == 0) {
+               if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe),
+                                               urb->transfer_buffer,
+                                               urb->actual_length) < 0) {
+                       BT_ERR("%s corrupted event packet", hdev->name);
+                       hdev->stat.err_rx++;
+               }
        }
 
-       urb = data->tx_urb;
-       if (urb->status == -EINPROGRESS)
-               skb = NULL;
-       else
-               skb = skb_dequeue(&data->tx_queue);
-
-       if (skb) {
-               skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
-               urb->transfer_buffer_length = skb->len;
-
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err < 0 && err != -ENODEV) {
-                       BT_ERR("%s submit failed for command urb %p with error %d",
-                                                       data->hdev->name, urb, err);
-                       skb_queue_head(&data->tx_queue, skb);
-               } else
-                       kfree_skb(skb);
+       usb_anchor_urb(urb, &data->rx_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p failed to resubmit (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
        }
 }
 
-static void bpa10x_complete(struct urb *urb)
+static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
 {
-       struct bpa10x_data *data = urb->context;
-       unsigned char *buf = urb->transfer_buffer;
-       int err, count = urb->actual_length;
+       struct bpa10x_data *data = hdev->driver_data;
+       struct urb *urb;
+       unsigned char *buf;
+       unsigned int pipe;
+       int err, size = 16;
 
-       BT_DBG("data %p urb %p buf %p count %d", data, urb, buf, count);
+       BT_DBG("%s", hdev->name);
 
-       read_lock(&data->lock);
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!urb)
+               return -ENOMEM;
 
-       if (!test_bit(HCI_RUNNING, &data->hdev->flags))
-               goto unlock;
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
 
-       if (urb->status < 0 || !count)
-               goto resubmit;
+       pipe = usb_rcvintpipe(data->udev, 0x81);
 
-       if (usb_pipein(urb->pipe)) {
-               data->hdev->stat.byte_rx += count;
+       usb_fill_int_urb(urb, data->udev, pipe, buf, size,
+                                               bpa10x_rx_complete, hdev, 1);
 
-               if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
-                       bpa10x_recv_event(data, buf, count);
+       urb->transfer_flags |= URB_FREE_BUFFER;
 
-               if (usb_pipetype(urb->pipe) == PIPE_BULK)
-                       bpa10x_recv_bulk(data, buf, count);
-       } else {
-               data->hdev->stat.byte_tx += count;
+       usb_anchor_urb(urb, &data->rx_anchor);
 
-               bpa10x_wakeup(data);
+       err = usb_submit_urb(urb, GFP_KERNEL);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+               kfree(buf);
        }
 
-resubmit:
-       if (usb_pipein(urb->pipe)) {
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err < 0 && err != -ENODEV) {
-                       BT_ERR("%s urb %p type %d resubmit status %d",
-                               data->hdev->name, urb, usb_pipetype(urb->pipe), err);
-               }
-       }
+       usb_free_urb(urb);
 
-unlock:
-       read_unlock(&data->lock);
+       return err;
 }
 
-static inline struct urb *bpa10x_alloc_urb(struct usb_device *udev, unsigned int pipe,
-                                       size_t size, gfp_t flags, void *data)
+static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
 {
+       struct bpa10x_data *data = hdev->driver_data;
        struct urb *urb;
-       struct usb_ctrlrequest *cr;
        unsigned char *buf;
+       unsigned int pipe;
+       int err, size = 64;
 
-       BT_DBG("udev %p data %p", udev, data);
+       BT_DBG("%s", hdev->name);
 
-       urb = usb_alloc_urb(0, flags);
+       urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!urb)
-               return NULL;
+               return -ENOMEM;
 
-       buf = kmalloc(size, flags);
+       buf = kmalloc(size, GFP_KERNEL);
        if (!buf) {
                usb_free_urb(urb);
-               return NULL;
+               return -ENOMEM;
        }
 
-       switch (usb_pipetype(pipe)) {
-       case PIPE_CONTROL:
-               cr = kmalloc(sizeof(*cr), flags);
-               if (!cr) {
-                       kfree(buf);
-                       usb_free_urb(urb);
-                       return NULL;
-               }
+       pipe = usb_rcvbulkpipe(data->udev, 0x82);
 
-               cr->bRequestType = USB_TYPE_VENDOR;
-               cr->bRequest     = 0;
-               cr->wIndex       = 0;
-               cr->wValue       = 0;
-               cr->wLength      = __cpu_to_le16(0);
+       usb_fill_bulk_urb(urb, data->udev, pipe,
+                                       buf, size, bpa10x_rx_complete, hdev);
 
-               usb_fill_control_urb(urb, udev, pipe, (void *) cr, buf, 0, bpa10x_complete, data);
-               break;
+       urb->transfer_flags |= URB_FREE_BUFFER;
 
-       case PIPE_INTERRUPT:
-               usb_fill_int_urb(urb, udev, pipe, buf, size, bpa10x_complete, data, 1);
-               break;
+       usb_anchor_urb(urb, &data->rx_anchor);
 
-       case PIPE_BULK:
-               usb_fill_bulk_urb(urb, udev, pipe, buf, size, bpa10x_complete, data);
-               break;
-
-       default:
+       err = usb_submit_urb(urb, GFP_KERNEL);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
                kfree(buf);
-               usb_free_urb(urb);
-               return NULL;
        }
 
-       return urb;
-}
-
-static inline void bpa10x_free_urb(struct urb *urb)
-{
-       BT_DBG("urb %p", urb);
-
-       if (!urb)
-               return;
-
-       kfree(urb->setup_packet);
-       kfree(urb->transfer_buffer);
-
        usb_free_urb(urb);
+
+       return err;
 }
 
 static int bpa10x_open(struct hci_dev *hdev)
 {
        struct bpa10x_data *data = hdev->driver_data;
-       struct usb_device *udev = data->udev;
-       unsigned long flags;
        int err;
 
-       BT_DBG("hdev %p data %p", hdev, data);
+       BT_DBG("%s", hdev->name);
 
        if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
                return 0;
 
-       data->cmd_urb = bpa10x_alloc_urb(udev, usb_sndctrlpipe(udev, BPA10X_CMD_EP),
-                                       BPA10X_CMD_BUF_SIZE, GFP_KERNEL, data);
-       if (!data->cmd_urb) {
-               err = -ENOMEM;
-               goto done;
-       }
-
-       data->evt_urb = bpa10x_alloc_urb(udev, usb_rcvintpipe(udev, BPA10X_EVT_EP),
-                                       BPA10X_EVT_BUF_SIZE, GFP_KERNEL, data);
-       if (!data->evt_urb) {
-               bpa10x_free_urb(data->cmd_urb);
-               err = -ENOMEM;
-               goto done;
-       }
-
-       data->rx_urb = bpa10x_alloc_urb(udev, usb_rcvbulkpipe(udev, BPA10X_RX_EP),
-                                       BPA10X_RX_BUF_SIZE, GFP_KERNEL, data);
-       if (!data->rx_urb) {
-               bpa10x_free_urb(data->evt_urb);
-               bpa10x_free_urb(data->cmd_urb);
-               err = -ENOMEM;
-               goto done;
-       }
-
-       data->tx_urb = bpa10x_alloc_urb(udev, usb_sndbulkpipe(udev, BPA10X_TX_EP),
-                                       BPA10X_TX_BUF_SIZE, GFP_KERNEL, data);
-       if (!data->rx_urb) {
-               bpa10x_free_urb(data->rx_urb);
-               bpa10x_free_urb(data->evt_urb);
-               bpa10x_free_urb(data->cmd_urb);
-               err = -ENOMEM;
-               goto done;
-       }
+       err = bpa10x_submit_intr_urb(hdev);
+       if (err < 0)
+               goto error;
 
-       write_lock_irqsave(&data->lock, flags);
+       err = bpa10x_submit_bulk_urb(hdev);
+       if (err < 0)
+               goto error;
 
-       err = usb_submit_urb(data->evt_urb, GFP_ATOMIC);
-       if (err < 0) {
-               BT_ERR("%s submit failed for event urb %p with error %d",
-                                       data->hdev->name, data->evt_urb, err);
-       } else {
-               err = usb_submit_urb(data->rx_urb, GFP_ATOMIC);
-               if (err < 0) {
-                       BT_ERR("%s submit failed for rx urb %p with error %d",
-                                       data->hdev->name, data->evt_urb, err);
-                       usb_kill_urb(data->evt_urb);
-               }
-       }
+       return 0;
 
-       write_unlock_irqrestore(&data->lock, flags);
+error:
+       usb_kill_anchored_urbs(&data->rx_anchor);
 
-done:
-       if (err < 0)
-               clear_bit(HCI_RUNNING, &hdev->flags);
+       clear_bit(HCI_RUNNING, &hdev->flags);
 
        return err;
 }
@@ -446,27 +339,13 @@ done:
 static int bpa10x_close(struct hci_dev *hdev)
 {
        struct bpa10x_data *data = hdev->driver_data;
-       unsigned long flags;
 
-       BT_DBG("hdev %p data %p", hdev, data);
+       BT_DBG("%s", hdev->name);
 
        if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
                return 0;
 
-       write_lock_irqsave(&data->lock, flags);
-
-       skb_queue_purge(&data->cmd_queue);
-       usb_kill_urb(data->cmd_urb);
-       usb_kill_urb(data->evt_urb);
-       usb_kill_urb(data->rx_urb);
-       usb_kill_urb(data->tx_urb);
-
-       write_unlock_irqrestore(&data->lock, flags);
-
-       bpa10x_free_urb(data->cmd_urb);
-       bpa10x_free_urb(data->evt_urb);
-       bpa10x_free_urb(data->rx_urb);
-       bpa10x_free_urb(data->tx_urb);
+       usb_kill_anchored_urbs(&data->rx_anchor);
 
        return 0;
 }
@@ -475,9 +354,9 @@ static int bpa10x_flush(struct hci_dev *hdev)
 {
        struct bpa10x_data *data = hdev->driver_data;
 
-       BT_DBG("hdev %p data %p", hdev, data);
+       BT_DBG("%s", hdev->name);
 
-       skb_queue_purge(&data->cmd_queue);
+       usb_kill_anchored_urbs(&data->tx_anchor);
 
        return 0;
 }
@@ -485,45 +364,78 @@ static int bpa10x_flush(struct hci_dev *hdev)
 static int bpa10x_send_frame(struct sk_buff *skb)
 {
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-       struct bpa10x_data *data;
-
-       BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
+       struct bpa10x_data *data = hdev->driver_data;
+       struct usb_ctrlrequest *dr;
+       struct urb *urb;
+       unsigned int pipe;
+       int err;
 
-       if (!hdev) {
-               BT_ERR("Frame for unknown HCI device");
-               return -ENODEV;
-       }
+       BT_DBG("%s", hdev->name);
 
        if (!test_bit(HCI_RUNNING, &hdev->flags))
                return -EBUSY;
 
-       data = hdev->driver_data;
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb)
+               return -ENOMEM;
 
        /* Prepend skb with frame type */
-       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+       *skb_push(skb, 1) = bt_cb(skb)->pkt_type;
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
+               dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+               if (!dr) {
+                       usb_free_urb(urb);
+                       return -ENOMEM;
+               }
+
+               dr->bRequestType = USB_TYPE_VENDOR;
+               dr->bRequest     = 0;
+               dr->wIndex       = 0;
+               dr->wValue       = 0;
+               dr->wLength      = __cpu_to_le16(skb->len);
+
+               pipe = usb_sndctrlpipe(data->udev, 0x00);
+
+               usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
+                               skb->data, skb->len, bpa10x_tx_complete, skb);
+
                hdev->stat.cmd_tx++;
-               skb_queue_tail(&data->cmd_queue, skb);
                break;
 
        case HCI_ACLDATA_PKT:
+               pipe = usb_sndbulkpipe(data->udev, 0x02);
+
+               usb_fill_bulk_urb(urb, data->udev, pipe,
+                               skb->data, skb->len, bpa10x_tx_complete, skb);
+
                hdev->stat.acl_tx++;
-               skb_queue_tail(&data->tx_queue, skb);
                break;
 
        case HCI_SCODATA_PKT:
+               pipe = usb_sndbulkpipe(data->udev, 0x02);
+
+               usb_fill_bulk_urb(urb, data->udev, pipe,
+                               skb->data, skb->len, bpa10x_tx_complete, skb);
+
                hdev->stat.sco_tx++;
-               skb_queue_tail(&data->tx_queue, skb);
                break;
-       };
 
-       read_lock(&data->lock);
+       default:
+               return -EILSEQ;
+       }
+
+       usb_anchor_urb(urb, &data->tx_anchor);
 
-       bpa10x_wakeup(data);
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed", hdev->name, urb);
+               kfree(urb->setup_packet);
+               usb_unanchor_urb(urb);
+       }
 
-       read_unlock(&data->lock);
+       usb_free_urb(urb);
 
        return 0;
 }
@@ -532,16 +444,17 @@ static void bpa10x_destruct(struct hci_dev *hdev)
 {
        struct bpa10x_data *data = hdev->driver_data;
 
-       BT_DBG("hdev %p data %p", hdev, data);
+       BT_DBG("%s", hdev->name);
 
+       kfree(data->rx_skb[0]);
+       kfree(data->rx_skb[1]);
        kfree(data);
 }
 
 static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct hci_dev *hdev;
        struct bpa10x_data *data;
+       struct hci_dev *hdev;
        int err;
 
        BT_DBG("intf %p id %p", intf, id);
@@ -549,48 +462,43 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
        if (ignore)
                return -ENODEV;
 
-       if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
+       if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
                return -ENODEV;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               BT_ERR("Can't allocate data structure");
+       if (!data)
                return -ENOMEM;
-       }
-
-       data->udev = udev;
 
-       rwlock_init(&data->lock);
+       data->udev = interface_to_usbdev(intf);
 
-       skb_queue_head_init(&data->cmd_queue);
-       skb_queue_head_init(&data->tx_queue);
+       init_usb_anchor(&data->tx_anchor);
+       init_usb_anchor(&data->rx_anchor);
 
        hdev = hci_alloc_dev();
        if (!hdev) {
-               BT_ERR("Can't allocate HCI device");
                kfree(data);
                return -ENOMEM;
        }
 
-       data->hdev = hdev;
-
        hdev->type = HCI_USB;
        hdev->driver_data = data;
+
+       data->hdev = hdev;
+
        SET_HCIDEV_DEV(hdev, &intf->dev);
 
-       hdev->open      = bpa10x_open;
-       hdev->close     = bpa10x_close;
-       hdev->flush     = bpa10x_flush;
-       hdev->send      = bpa10x_send_frame;
-       hdev->destruct  = bpa10x_destruct;
+       hdev->open     = bpa10x_open;
+       hdev->close    = bpa10x_close;
+       hdev->flush    = bpa10x_flush;
+       hdev->send     = bpa10x_send_frame;
+       hdev->destruct = bpa10x_destruct;
 
        hdev->owner = THIS_MODULE;
 
        err = hci_register_dev(hdev);
        if (err < 0) {
-               BT_ERR("Can't register HCI device");
-               kfree(data);
                hci_free_dev(hdev);
+               kfree(data);
                return err;
        }
 
@@ -602,19 +510,17 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 static void bpa10x_disconnect(struct usb_interface *intf)
 {
        struct bpa10x_data *data = usb_get_intfdata(intf);
-       struct hci_dev *hdev = data->hdev;
 
        BT_DBG("intf %p", intf);
 
-       if (!hdev)
+       if (!data)
                return;
 
        usb_set_intfdata(intf, NULL);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
+       hci_unregister_dev(data->hdev);
 
-       hci_free_dev(hdev);
+       hci_free_dev(data->hdev);
 }
 
 static struct usb_driver bpa10x_driver = {
@@ -626,15 +532,9 @@ static struct usb_driver bpa10x_driver = {
 
 static int __init bpa10x_init(void)
 {
-       int err;
-
        BT_INFO("Digianswer Bluetooth USB driver ver %s", VERSION);
 
-       err = usb_register(&bpa10x_driver);
-       if (err < 0)
-               BT_ERR("Failed to register USB driver");
-
-       return err;
+       return usb_register(&bpa10x_driver);
 }
 
 static void __exit bpa10x_exit(void)
index 3951607..a18f9b8 100644 (file)
@@ -344,10 +344,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
        unsigned int iobase;
        int iir;
 
-       if (!info || !info->hdev) {
-               BT_ERR("Call of irq %d for unknown device", irq);
-               return IRQ_NONE;
-       }
+       BUG_ON(!info->hdev);
 
        iobase = info->p_dev->io.BasePort1;
 
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
new file mode 100644 (file)
index 0000000..b786f61
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ *
+ *  Generic Bluetooth SDIO driver
+ *
+ *  Copyright (C) 2007  Cambridge Silicon Radio Ltd.
+ *  Copyright (C) 2007  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#ifndef CONFIG_BT_HCIBTSDIO_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "0.1"
+
+static const struct sdio_device_id btsdio_table[] = {
+       /* Generic Bluetooth Type-A SDIO device */
+       { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_A) },
+
+       /* Generic Bluetooth Type-B SDIO device */
+       { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
+
+       { }     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(sdio, btsdio_table);
+
+struct btsdio_data {
+       struct hci_dev   *hdev;
+       struct sdio_func *func;
+
+       struct work_struct work;
+
+       struct sk_buff_head txq;
+};
+
+#define REG_RDAT     0x00      /* Receiver Data */
+#define REG_TDAT     0x00      /* Transmitter Data */
+#define REG_PC_RRT   0x10      /* Read Packet Control */
+#define REG_PC_WRT   0x11      /* Write Packet Control */
+#define REG_RTC_STAT 0x12      /* Retry Control Status */
+#define REG_RTC_SET  0x12      /* Retry Control Set */
+#define REG_INTRD    0x13      /* Interrupt Indication */
+#define REG_CL_INTRD 0x13      /* Interrupt Clear */
+#define REG_EN_INTRD 0x14      /* Interrupt Enable */
+#define REG_MD_STAT  0x20      /* Bluetooth Mode Status */
+
+static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb)
+{
+       int err;
+
+       BT_DBG("%s", data->hdev->name);
+
+       /* Prepend Type-A header */
+       skb_push(skb, 4);
+       skb->data[0] = (skb->len & 0x0000ff);
+       skb->data[1] = (skb->len & 0x00ff00) >> 8;
+       skb->data[2] = (skb->len & 0xff0000) >> 16;
+       skb->data[3] = bt_cb(skb)->pkt_type;
+
+       err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len);
+       if (err < 0) {
+               sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL);
+               return err;
+       }
+
+       data->hdev->stat.byte_tx += skb->len;
+
+       kfree_skb(skb);
+
+       return 0;
+}
+
+static void btsdio_work(struct work_struct *work)
+{
+       struct btsdio_data *data = container_of(work, struct btsdio_data, work);
+       struct sk_buff *skb;
+       int err;
+
+       BT_DBG("%s", data->hdev->name);
+
+       sdio_claim_host(data->func);
+
+       while ((skb = skb_dequeue(&data->txq))) {
+               err = btsdio_tx_packet(data, skb);
+               if (err < 0) {
+                       data->hdev->stat.err_tx++;
+                       skb_queue_head(&data->txq, skb);
+                       break;
+               }
+       }
+
+       sdio_release_host(data->func);
+}
+
+static int btsdio_rx_packet(struct btsdio_data *data)
+{
+       u8 hdr[4] __attribute__ ((aligned(4)));
+       struct sk_buff *skb;
+       int err, len;
+
+       BT_DBG("%s", data->hdev->name);
+
+       err = sdio_readsb(data->func, hdr, REG_RDAT, 4);
+       if (err < 0)
+               return err;
+
+       len = hdr[0] | (hdr[1] << 8) | (hdr[2] << 16);
+       if (len < 4 || len > 65543)
+               return -EILSEQ;
+
+       skb = bt_skb_alloc(len - 4, GFP_KERNEL);
+       if (!skb) {
+               /* Out of memory. Prepare a read retry and just
+                * return with the expectation that the next time
+                * we're called we'll have more memory. */
+               return -ENOMEM;
+       }
+
+       skb_put(skb, len - 4);
+
+       err = sdio_readsb(data->func, skb->data, REG_RDAT, len - 4);
+       if (err < 0) {
+               kfree(skb);
+               return err;
+       }
+
+       data->hdev->stat.byte_rx += len;
+
+       skb->dev = (void *) data->hdev;
+       bt_cb(skb)->pkt_type = hdr[3];
+
+       err = hci_recv_frame(skb);
+       if (err < 0) {
+               kfree(skb);
+               return err;
+       }
+
+       sdio_writeb(data->func, 0x00, REG_PC_RRT, NULL);
+
+       return 0;
+}
+
+static void btsdio_interrupt(struct sdio_func *func)
+{
+       struct btsdio_data *data = sdio_get_drvdata(func);
+       int intrd;
+
+       BT_DBG("%s", data->hdev->name);
+
+       intrd = sdio_readb(func, REG_INTRD, NULL);
+       if (intrd & 0x01) {
+               sdio_writeb(func, 0x01, REG_CL_INTRD, NULL);
+
+               if (btsdio_rx_packet(data) < 0) {
+                       data->hdev->stat.err_rx++;
+                       sdio_writeb(data->func, 0x01, REG_PC_RRT, NULL);
+               }
+       }
+}
+
+static int btsdio_open(struct hci_dev *hdev)
+{
+       struct btsdio_data *data = hdev->driver_data;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       sdio_claim_host(data->func);
+
+       err = sdio_enable_func(data->func);
+       if (err < 0) {
+               clear_bit(HCI_RUNNING, &hdev->flags);
+               goto release;
+       }
+
+       err = sdio_claim_irq(data->func, btsdio_interrupt);
+       if (err < 0) {
+               sdio_disable_func(data->func);
+               clear_bit(HCI_RUNNING, &hdev->flags);
+               goto release;
+       }
+
+       if (data->func->class == SDIO_CLASS_BT_B)
+               sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL);
+
+       sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL);
+
+release:
+       sdio_release_host(data->func);
+
+       return err;
+}
+
+static int btsdio_close(struct hci_dev *hdev)
+{
+       struct btsdio_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       sdio_claim_host(data->func);
+
+       sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
+
+       sdio_release_irq(data->func);
+       sdio_disable_func(data->func);
+
+       sdio_release_host(data->func);
+
+       return 0;
+}
+
+static int btsdio_flush(struct hci_dev *hdev)
+{
+       struct btsdio_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       skb_queue_purge(&data->txq);
+
+       return 0;
+}
+
+static int btsdio_send_frame(struct sk_buff *skb)
+{
+       struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+       struct btsdio_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return -EBUSY;
+
+       switch (bt_cb(skb)->pkt_type) {
+       case HCI_COMMAND_PKT:
+               hdev->stat.cmd_tx++;
+               break;
+
+       case HCI_ACLDATA_PKT:
+               hdev->stat.acl_tx++;
+               break;
+
+       case HCI_SCODATA_PKT:
+               hdev->stat.sco_tx++;
+               break;
+
+       default:
+               return -EILSEQ;
+       }
+
+       skb_queue_tail(&data->txq, skb);
+
+       schedule_work(&data->work);
+
+       return 0;
+}
+
+static void btsdio_destruct(struct hci_dev *hdev)
+{
+       struct btsdio_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       kfree(data);
+}
+
+static int btsdio_probe(struct sdio_func *func,
+                               const struct sdio_device_id *id)
+{
+       struct btsdio_data *data;
+       struct hci_dev *hdev;
+       struct sdio_func_tuple *tuple = func->tuples;
+       int err;
+
+       BT_DBG("func %p id %p class 0x%04x", func, id, func->class);
+
+       while (tuple) {
+               BT_DBG("code 0x%x size %d", tuple->code, tuple->size);
+               tuple = tuple->next;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->func = func;
+
+       INIT_WORK(&data->work, btsdio_work);
+
+       skb_queue_head_init(&data->txq);
+
+       hdev = hci_alloc_dev();
+       if (!hdev) {
+               kfree(data);
+               return -ENOMEM;
+       }
+
+       hdev->type = HCI_SDIO;
+       hdev->driver_data = data;
+
+       data->hdev = hdev;
+
+       SET_HCIDEV_DEV(hdev, &func->dev);
+
+       hdev->open     = btsdio_open;
+       hdev->close    = btsdio_close;
+       hdev->flush    = btsdio_flush;
+       hdev->send     = btsdio_send_frame;
+       hdev->destruct = btsdio_destruct;
+
+       hdev->owner = THIS_MODULE;
+
+       err = hci_register_dev(hdev);
+       if (err < 0) {
+               hci_free_dev(hdev);
+               kfree(data);
+               return err;
+       }
+
+       sdio_set_drvdata(func, data);
+
+       return 0;
+}
+
+static void btsdio_remove(struct sdio_func *func)
+{
+       struct btsdio_data *data = sdio_get_drvdata(func);
+       struct hci_dev *hdev;
+
+       BT_DBG("func %p", func);
+
+       if (!data)
+               return;
+
+       hdev = data->hdev;
+
+       sdio_set_drvdata(func, NULL);
+
+       hci_unregister_dev(hdev);
+
+       hci_free_dev(hdev);
+}
+
+static struct sdio_driver btsdio_driver = {
+       .name           = "btsdio",
+       .probe          = btsdio_probe,
+       .remove         = btsdio_remove,
+       .id_table       = btsdio_table,
+};
+
+static int __init btsdio_init(void)
+{
+       BT_INFO("Generic Bluetooth SDIO driver ver %s", VERSION);
+
+       return sdio_register_driver(&btsdio_driver);
+}
+
+static void __exit btsdio_exit(void)
+{
+       sdio_unregister_driver(&btsdio_driver);
+}
+
+module_init(btsdio_init);
+module_exit(btsdio_exit);
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Generic Bluetooth SDIO driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
index d7d2ea0..08f48d5 100644 (file)
@@ -294,10 +294,7 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
        int boguscount = 0;
        int iir, lsr;
 
-       if (!info || !info->hdev) {
-               BT_ERR("Call of irq %d for unknown device", irq);
-               return IRQ_NONE;
-       }
+       BUG_ON(!info->hdev);
 
        iobase = info->p_dev->io.BasePort1;
 
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
new file mode 100644 (file)
index 0000000..12e1089
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ *
+ *  Generic Bluetooth USB driver
+ *
+ *  Copyright (C) 2005-2007  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+
+#include <linux/usb.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+//#define CONFIG_BT_HCIBTUSB_DEBUG
+#ifndef CONFIG_BT_HCIBTUSB_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "0.1"
+
+static struct usb_device_id btusb_table[] = {
+       /* Generic Bluetooth USB device */
+       { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+
+       { }     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, btusb_table);
+
+static struct usb_device_id blacklist_table[] = {
+       { }     /* Terminating entry */
+};
+
+#define BTUSB_INTR_RUNNING     0
+#define BTUSB_BULK_RUNNING     1
+
+struct btusb_data {
+       struct hci_dev       *hdev;
+       struct usb_device    *udev;
+
+       spinlock_t lock;
+
+       unsigned long flags;
+
+       struct work_struct work;
+
+       struct usb_anchor tx_anchor;
+       struct usb_anchor intr_anchor;
+       struct usb_anchor bulk_anchor;
+
+       struct usb_endpoint_descriptor *intr_ep;
+       struct usb_endpoint_descriptor *bulk_tx_ep;
+       struct usb_endpoint_descriptor *bulk_rx_ep;
+};
+
+static void btusb_intr_complete(struct urb *urb)
+{
+       struct hci_dev *hdev = urb->context;
+       struct btusb_data *data = hdev->driver_data;
+       int err;
+
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return;
+
+       if (urb->status == 0) {
+               if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
+                                               urb->transfer_buffer,
+                                               urb->actual_length) < 0) {
+                       BT_ERR("%s corrupted event packet", hdev->name);
+                       hdev->stat.err_rx++;
+               }
+       }
+
+       if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
+               return;
+
+       usb_anchor_urb(urb, &data->intr_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p failed to resubmit (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+       }
+}
+
+static inline int btusb_submit_intr_urb(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+       struct urb *urb;
+       unsigned char *buf;
+       unsigned int pipe;
+       int err, size;
+
+       BT_DBG("%s", hdev->name);
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb)
+               return -ENOMEM;
+
+       size = le16_to_cpu(data->intr_ep->wMaxPacketSize);
+
+       buf = kmalloc(size, GFP_ATOMIC);
+       if (!buf) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
+
+       pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);
+
+       usb_fill_int_urb(urb, data->udev, pipe, buf, size,
+                                               btusb_intr_complete, hdev,
+                                               data->intr_ep->bInterval);
+
+       urb->transfer_flags |= URB_FREE_BUFFER;
+
+       usb_anchor_urb(urb, &data->intr_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+               kfree(buf);
+       }
+
+       usb_free_urb(urb);
+
+       return err;
+}
+
+static void btusb_bulk_complete(struct urb *urb)
+{
+       struct hci_dev *hdev = urb->context;
+       struct btusb_data *data = hdev->driver_data;
+       int err;
+
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return;
+
+       if (urb->status == 0) {
+               if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
+                                               urb->transfer_buffer,
+                                               urb->actual_length) < 0) {
+                       BT_ERR("%s corrupted ACL packet", hdev->name);
+                       hdev->stat.err_rx++;
+               }
+       }
+
+       if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
+               return;
+
+       usb_anchor_urb(urb, &data->bulk_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p failed to resubmit (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+       }
+}
+
+static inline int btusb_submit_bulk_urb(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+       struct urb *urb;
+       unsigned char *buf;
+       unsigned int pipe;
+       int err, size;
+
+       BT_DBG("%s", hdev->name);
+
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!urb)
+               return -ENOMEM;
+
+       size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize);
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
+
+       pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
+
+       usb_fill_bulk_urb(urb, data->udev, pipe,
+                                       buf, size, btusb_bulk_complete, hdev);
+
+       urb->transfer_flags |= URB_FREE_BUFFER;
+
+       usb_anchor_urb(urb, &data->bulk_anchor);
+
+       err = usb_submit_urb(urb, GFP_KERNEL);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+               kfree(buf);
+       }
+
+       usb_free_urb(urb);
+
+       return err;
+}
+
+static void btusb_tx_complete(struct urb *urb)
+{
+       struct sk_buff *skb = urb->context;
+       struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               goto done;
+
+       if (!urb->status)
+               hdev->stat.byte_tx += urb->transfer_buffer_length;
+       else
+               hdev->stat.err_tx++;
+
+done:
+       kfree(urb->setup_packet);
+
+       kfree_skb(skb);
+}
+
+static int btusb_open(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
+               return 0;
+
+       err = btusb_submit_intr_urb(hdev);
+       if (err < 0) {
+               clear_bit(BTUSB_INTR_RUNNING, &hdev->flags);
+               clear_bit(HCI_RUNNING, &hdev->flags);
+       }
+
+       return err;
+}
+
+static int btusb_close(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+       usb_kill_anchored_urbs(&data->bulk_anchor);
+
+       clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+       usb_kill_anchored_urbs(&data->intr_anchor);
+
+       return 0;
+}
+
+static int btusb_flush(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       usb_kill_anchored_urbs(&data->tx_anchor);
+
+       return 0;
+}
+
+static int btusb_send_frame(struct sk_buff *skb)
+{
+       struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+       struct btusb_data *data = hdev->driver_data;
+       struct usb_ctrlrequest *dr;
+       struct urb *urb;
+       unsigned int pipe;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return -EBUSY;
+
+       switch (bt_cb(skb)->pkt_type) {
+       case HCI_COMMAND_PKT:
+               urb = usb_alloc_urb(0, GFP_ATOMIC);
+               if (!urb)
+                       return -ENOMEM;
+
+               dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+               if (!dr) {
+                       usb_free_urb(urb);
+                       return -ENOMEM;
+               }
+
+               dr->bRequestType = USB_TYPE_CLASS;
+               dr->bRequest     = 0;
+               dr->wIndex       = 0;
+               dr->wValue       = 0;
+               dr->wLength      = __cpu_to_le16(skb->len);
+
+               pipe = usb_sndctrlpipe(data->udev, 0x00);
+
+               usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
+                               skb->data, skb->len, btusb_tx_complete, skb);
+
+               hdev->stat.cmd_tx++;
+               break;
+
+       case HCI_ACLDATA_PKT:
+               urb = usb_alloc_urb(0, GFP_ATOMIC);
+               if (!urb)
+                       return -ENOMEM;
+
+               pipe = usb_sndbulkpipe(data->udev,
+                                       data->bulk_tx_ep->bEndpointAddress);
+
+               usb_fill_bulk_urb(urb, data->udev, pipe,
+                               skb->data, skb->len, btusb_tx_complete, skb);
+
+               hdev->stat.acl_tx++;
+               break;
+
+       case HCI_SCODATA_PKT:
+               hdev->stat.sco_tx++;
+               kfree_skb(skb);
+               return 0;
+
+       default:
+               return -EILSEQ;
+       }
+
+       usb_anchor_urb(urb, &data->tx_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed", hdev->name, urb);
+               kfree(urb->setup_packet);
+               usb_unanchor_urb(urb);
+       }
+
+       usb_free_urb(urb);
+
+       return err;
+}
+
+static void btusb_destruct(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       kfree(data);
+}
+
+static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
+{
+       struct btusb_data *data = hdev->driver_data;
+
+       BT_DBG("%s evt %d", hdev->name, evt);
+
+       if (evt == HCI_NOTIFY_CONN_ADD || evt == HCI_NOTIFY_CONN_DEL)
+               schedule_work(&data->work);
+}
+
+static void btusb_work(struct work_struct *work)
+{
+       struct btusb_data *data = container_of(work, struct btusb_data, work);
+       struct hci_dev *hdev = data->hdev;
+
+       if (hdev->conn_hash.acl_num == 0) {
+               clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+               usb_kill_anchored_urbs(&data->bulk_anchor);
+               return;
+       }
+
+       if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
+               if (btusb_submit_bulk_urb(hdev) < 0)
+                       clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+               else
+                       btusb_submit_bulk_urb(hdev);
+       }
+}
+
+static int btusb_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       struct usb_endpoint_descriptor *ep_desc;
+       struct btusb_data *data;
+       struct hci_dev *hdev;
+       int i, err;
+
+       BT_DBG("intf %p id %p", intf, id);
+
+       if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+               return -ENODEV;
+
+       if (!id->driver_info) {
+               const struct usb_device_id *match;
+               match = usb_match_id(intf, blacklist_table);
+               if (match)
+                       id = match;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+               ep_desc = &intf->cur_altsetting->endpoint[i].desc;
+
+               if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) {
+                       data->intr_ep = ep_desc;
+                       continue;
+               }
+
+               if (!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) {
+                       data->bulk_tx_ep = ep_desc;
+                       continue;
+               }
+
+               if (!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) {
+                       data->bulk_rx_ep = ep_desc;
+                       continue;
+               }
+       }
+
+       if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
+               kfree(data);
+               return -ENODEV;
+       }
+
+       data->udev = interface_to_usbdev(intf);
+
+       spin_lock_init(&data->lock);
+
+       INIT_WORK(&data->work, btusb_work);
+
+       init_usb_anchor(&data->tx_anchor);
+       init_usb_anchor(&data->intr_anchor);
+       init_usb_anchor(&data->bulk_anchor);
+
+       hdev = hci_alloc_dev();
+       if (!hdev) {
+               kfree(data);
+               return -ENOMEM;
+       }
+
+       hdev->type = HCI_USB;
+       hdev->driver_data = data;
+
+       data->hdev = hdev;
+
+       SET_HCIDEV_DEV(hdev, &intf->dev);
+
+       hdev->open     = btusb_open;
+       hdev->close    = btusb_close;
+       hdev->flush    = btusb_flush;
+       hdev->send     = btusb_send_frame;
+       hdev->destruct = btusb_destruct;
+       hdev->notify   = btusb_notify;
+
+       hdev->owner = THIS_MODULE;
+
+       set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+
+       err = hci_register_dev(hdev);
+       if (err < 0) {
+               hci_free_dev(hdev);
+               kfree(data);
+               return err;
+       }
+
+       usb_set_intfdata(intf, data);
+
+       return 0;
+}
+
+static void btusb_disconnect(struct usb_interface *intf)
+{
+       struct btusb_data *data = usb_get_intfdata(intf);
+       struct hci_dev *hdev;
+
+       BT_DBG("intf %p", intf);
+
+       if (!data)
+               return;
+
+       hdev = data->hdev;
+
+       usb_set_intfdata(intf, NULL);
+
+       hci_unregister_dev(hdev);
+
+       hci_free_dev(hdev);
+}
+
+static struct usb_driver btusb_driver = {
+       .name           = "btusb",
+       .probe          = btusb_probe,
+       .disconnect     = btusb_disconnect,
+       .id_table       = btusb_table,
+};
+
+static int __init btusb_init(void)
+{
+       BT_INFO("Generic Bluetooth USB driver ver %s", VERSION);
+
+       return usb_register(&btusb_driver);
+}
+
+static void __exit btusb_exit(void)
+{
+       usb_deregister(&btusb_driver);
+}
+
+module_init(btusb_init);
+module_exit(btusb_exit);
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Generic Bluetooth USB driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
index 7f9c54b..dae45cd 100644 (file)
@@ -298,10 +298,7 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
        int boguscount = 0;
        int iir, lsr;
 
-       if (!info || !info->hdev) {
-               BT_ERR("Call of irq %d for unknown device", irq);
-               return IRQ_NONE;
-       }
+       BUG_ON(!info->hdev);
 
        iobase = info->p_dev->io.BasePort1;
 
index d66064c..696f752 100644 (file)
@@ -237,7 +237,8 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
        if (hciextn && chan == 5) {
                struct hci_command_hdr *hdr = (struct hci_command_hdr *) data;
 
-               if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == OGF_VENDOR_CMD) {
+               /* Vendor specific commands */
+               if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == 0x3f) {
                        u8 desc = *(data + HCI_COMMAND_HDR_SIZE);
                        if ((desc & 0xf0) == 0xc0) {
                                data += HCI_COMMAND_HDR_SIZE + 1;
index 6055b9c..e68821d 100644 (file)
@@ -549,7 +549,10 @@ static int __init hci_uart_init(void)
 #ifdef CONFIG_BT_HCIUART_BCSP
        bcsp_init();
 #endif
-       
+#ifdef CONFIG_BT_HCIUART_LL
+       ll_init();
+#endif
+
        return 0;
 }
 
@@ -563,6 +566,9 @@ static void __exit hci_uart_exit(void)
 #ifdef CONFIG_BT_HCIUART_BCSP
        bcsp_deinit();
 #endif
+#ifdef CONFIG_BT_HCIUART_LL
+       ll_deinit();
+#endif
 
        /* Release tty registration of line discipline */
        if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
new file mode 100644 (file)
index 0000000..8c3e62a
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ *  Texas Instruments' Bluetooth HCILL UART protocol
+ *
+ *  HCILL (HCI Low Level) is a Texas Instruments' power management
+ *  protocol extension to H4.
+ *
+ *  Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ *  Written by Ohad Ben-Cohen <ohad@bencohen.org>
+ *
+ *  Acknowledgements:
+ *  This file is based on hci_h4.c, which was written
+ *  by Maxim Krasnyansky and Marcel Holtmann.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+/* HCILL commands */
+#define HCILL_GO_TO_SLEEP_IND  0x30
+#define HCILL_GO_TO_SLEEP_ACK  0x31
+#define HCILL_WAKE_UP_IND      0x32
+#define HCILL_WAKE_UP_ACK      0x33
+
+/* HCILL receiver States */
+#define HCILL_W4_PACKET_TYPE   0
+#define HCILL_W4_EVENT_HDR     1
+#define HCILL_W4_ACL_HDR       2
+#define HCILL_W4_SCO_HDR       3
+#define HCILL_W4_DATA          4
+
+/* HCILL states */
+enum hcill_states_e {
+       HCILL_ASLEEP,
+       HCILL_ASLEEP_TO_AWAKE,
+       HCILL_AWAKE,
+       HCILL_AWAKE_TO_ASLEEP
+};
+
+struct hcill_cmd {
+       u8 cmd;
+} __attribute__((packed));
+
+struct ll_struct {
+       unsigned long rx_state;
+       unsigned long rx_count;
+       struct sk_buff *rx_skb;
+       struct sk_buff_head txq;
+       spinlock_t hcill_lock;          /* HCILL state lock     */
+       unsigned long hcill_state;      /* HCILL power state    */
+       struct sk_buff_head tx_wait_q;  /* HCILL wait queue     */
+};
+
+/*
+ * Builds and sends an HCILL command packet.
+ * These are very simple packets with only 1 cmd byte
+ */
+static int send_hcill_cmd(u8 cmd, struct hci_uart *hu)
+{
+       int err = 0;
+       struct sk_buff *skb = NULL;
+       struct ll_struct *ll = hu->priv;
+       struct hcill_cmd *hcill_packet;
+
+       BT_DBG("hu %p cmd 0x%x", hu, cmd);
+
+       /* allocate packet */
+       skb = bt_skb_alloc(1, GFP_ATOMIC);
+       if (!skb) {
+               BT_ERR("cannot allocate memory for HCILL packet");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* prepare packet */
+       hcill_packet = (struct hcill_cmd *) skb_put(skb, 1);
+       hcill_packet->cmd = cmd;
+       skb->dev = (void *) hu->hdev;
+
+       /* send packet */
+       skb_queue_tail(&ll->txq, skb);
+out:
+       return err;
+}
+
+/* Initialize protocol */
+static int ll_open(struct hci_uart *hu)
+{
+       struct ll_struct *ll;
+
+       BT_DBG("hu %p", hu);
+
+       ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
+       if (!ll)
+               return -ENOMEM;
+
+       skb_queue_head_init(&ll->txq);
+       skb_queue_head_init(&ll->tx_wait_q);
+       spin_lock_init(&ll->hcill_lock);
+
+       ll->hcill_state = HCILL_AWAKE;
+
+       hu->priv = ll;
+
+       return 0;
+}
+
+/* Flush protocol data */
+static int ll_flush(struct hci_uart *hu)
+{
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&ll->tx_wait_q);
+       skb_queue_purge(&ll->txq);
+
+       return 0;
+}
+
+/* Close protocol */
+static int ll_close(struct hci_uart *hu)
+{
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&ll->tx_wait_q);
+       skb_queue_purge(&ll->txq);
+
+       if (ll->rx_skb)
+               kfree_skb(ll->rx_skb);
+
+       hu->priv = NULL;
+
+       kfree(ll);
+
+       return 0;
+}
+
+/*
+ * internal function, which does common work of the device wake up process:
+ * 1. places all pending packets (waiting in tx_wait_q list) in txq list.
+ * 2. changes internal state to HCILL_AWAKE.
+ * Note: assumes that hcill_lock spinlock is taken,
+ * shouldn't be called otherwise!
+ */
+static void __ll_do_awake(struct ll_struct *ll)
+{
+       struct sk_buff *skb = NULL;
+
+       while ((skb = skb_dequeue(&ll->tx_wait_q)))
+               skb_queue_tail(&ll->txq, skb);
+
+       ll->hcill_state = HCILL_AWAKE;
+}
+
+/*
+ * Called upon a wake-up-indication from the device
+ */
+static void ll_device_want_to_wakeup(struct hci_uart *hu)
+{
+       unsigned long flags;
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       /* lock hcill state */
+       spin_lock_irqsave(&ll->hcill_lock, flags);
+
+       switch (ll->hcill_state) {
+       case HCILL_ASLEEP:
+               /* acknowledge device wake up */
+               if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
+                       BT_ERR("cannot acknowledge device wake up");
+                       goto out;
+               }
+               break;
+       case HCILL_ASLEEP_TO_AWAKE:
+               /*
+                * this state means that a wake-up-indication
+                * is already on its way to the device,
+                * and will serve as the required wake-up-ack
+                */
+               BT_DBG("dual wake-up-indication");
+               break;
+       default:
+               /* any other state are illegal */
+               BT_ERR("received HCILL_WAKE_UP_IND in state %ld", ll->hcill_state);
+               break;
+       }
+
+       /* send pending packets and change state to HCILL_AWAKE */
+       __ll_do_awake(ll);
+
+out:
+       spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+       /* actually send the packets */
+       hci_uart_tx_wakeup(hu);
+}
+
+/*
+ * Called upon a sleep-indication from the device
+ */
+static void ll_device_want_to_sleep(struct hci_uart *hu)
+{
+       unsigned long flags;
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       /* lock hcill state */
+       spin_lock_irqsave(&ll->hcill_lock, flags);
+
+       /* sanity check */
+       if (ll->hcill_state != HCILL_AWAKE)
+               BT_ERR("ERR: HCILL_GO_TO_SLEEP_IND in state %ld", ll->hcill_state);
+
+       /* acknowledge device sleep */
+       if (send_hcill_cmd(HCILL_GO_TO_SLEEP_ACK, hu) < 0) {
+               BT_ERR("cannot acknowledge device sleep");
+               goto out;
+       }
+
+       /* update state */
+       ll->hcill_state = HCILL_ASLEEP;
+
+out:
+       spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+       /* actually send the sleep ack packet */
+       hci_uart_tx_wakeup(hu);
+}
+
+/*
+ * Called upon wake-up-acknowledgement from the device
+ */
+static void ll_device_woke_up(struct hci_uart *hu)
+{
+       unsigned long flags;
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       /* lock hcill state */
+       spin_lock_irqsave(&ll->hcill_lock, flags);
+
+       /* sanity check */
+       if (ll->hcill_state != HCILL_ASLEEP_TO_AWAKE)
+               BT_ERR("received HCILL_WAKE_UP_ACK in state %ld", ll->hcill_state);
+
+       /* send pending packets and change state to HCILL_AWAKE */
+       __ll_do_awake(ll);
+
+       spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+       /* actually send the packets */
+       hci_uart_tx_wakeup(hu);
+}
+
+/* Enqueue frame for transmittion (padding, crc, etc) */
+/* may be called from two simultaneous tasklets */
+static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+       unsigned long flags = 0;
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p skb %p", hu, skb);
+
+       /* Prepend skb with frame type */
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+       /* lock hcill state */
+       spin_lock_irqsave(&ll->hcill_lock, flags);
+
+       /* act according to current state */
+       switch (ll->hcill_state) {
+       case HCILL_AWAKE:
+               BT_DBG("device awake, sending normally");
+               skb_queue_tail(&ll->txq, skb);
+               break;
+       case HCILL_ASLEEP:
+               BT_DBG("device asleep, waking up and queueing packet");
+               /* save packet for later */
+               skb_queue_tail(&ll->tx_wait_q, skb);
+               /* awake device */
+               if (send_hcill_cmd(HCILL_WAKE_UP_IND, hu) < 0) {
+                       BT_ERR("cannot wake up device");
+                       break;
+               }
+               ll->hcill_state = HCILL_ASLEEP_TO_AWAKE;
+               break;
+       case HCILL_ASLEEP_TO_AWAKE:
+               BT_DBG("device waking up, queueing packet");
+               /* transient state; just keep packet for later */
+               skb_queue_tail(&ll->tx_wait_q, skb);
+               break;
+       default:
+               BT_ERR("illegal hcill state: %ld (losing packet)", ll->hcill_state);
+               kfree_skb(skb);
+               break;
+       }
+
+       spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+       return 0;
+}
+
+static inline int ll_check_data_len(struct ll_struct *ll, int len)
+{
+       register int room = skb_tailroom(ll->rx_skb);
+
+       BT_DBG("len %d room %d", len, room);
+
+       if (!len) {
+               hci_recv_frame(ll->rx_skb);
+       } else if (len > room) {
+               BT_ERR("Data length is too large");
+               kfree_skb(ll->rx_skb);
+       } else {
+               ll->rx_state = HCILL_W4_DATA;
+               ll->rx_count = len;
+               return len;
+       }
+
+       ll->rx_state = HCILL_W4_PACKET_TYPE;
+       ll->rx_skb   = NULL;
+       ll->rx_count = 0;
+
+       return 0;
+}
+
+/* Recv data */
+static int ll_recv(struct hci_uart *hu, void *data, int count)
+{
+       struct ll_struct *ll = hu->priv;
+       register char *ptr;
+       struct hci_event_hdr *eh;
+       struct hci_acl_hdr   *ah;
+       struct hci_sco_hdr   *sh;
+       register int len, type, dlen;
+
+       BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
+
+       ptr = data;
+       while (count) {
+               if (ll->rx_count) {
+                       len = min_t(unsigned int, ll->rx_count, count);
+                       memcpy(skb_put(ll->rx_skb, len), ptr, len);
+                       ll->rx_count -= len; count -= len; ptr += len;
+
+                       if (ll->rx_count)
+                               continue;
+
+                       switch (ll->rx_state) {
+                       case HCILL_W4_DATA:
+                               BT_DBG("Complete data");
+                               hci_recv_frame(ll->rx_skb);
+
+                               ll->rx_state = HCILL_W4_PACKET_TYPE;
+                               ll->rx_skb = NULL;
+                               continue;
+
+                       case HCILL_W4_EVENT_HDR:
+                               eh = (struct hci_event_hdr *) ll->rx_skb->data;
+
+                               BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
+
+                               ll_check_data_len(ll, eh->plen);
+                               continue;
+
+                       case HCILL_W4_ACL_HDR:
+                               ah = (struct hci_acl_hdr *) ll->rx_skb->data;
+                               dlen = __le16_to_cpu(ah->dlen);
+
+                               BT_DBG("ACL header: dlen %d", dlen);
+
+                               ll_check_data_len(ll, dlen);
+                               continue;
+
+                       case HCILL_W4_SCO_HDR:
+                               sh = (struct hci_sco_hdr *) ll->rx_skb->data;
+
+                               BT_DBG("SCO header: dlen %d", sh->dlen);
+
+                               ll_check_data_len(ll, sh->dlen);
+                               continue;
+                       }
+               }
+
+               /* HCILL_W4_PACKET_TYPE */
+               switch (*ptr) {
+               case HCI_EVENT_PKT:
+                       BT_DBG("Event packet");
+                       ll->rx_state = HCILL_W4_EVENT_HDR;
+                       ll->rx_count = HCI_EVENT_HDR_SIZE;
+                       type = HCI_EVENT_PKT;
+                       break;
+
+               case HCI_ACLDATA_PKT:
+                       BT_DBG("ACL packet");
+                       ll->rx_state = HCILL_W4_ACL_HDR;
+                       ll->rx_count = HCI_ACL_HDR_SIZE;
+                       type = HCI_ACLDATA_PKT;
+                       break;
+
+               case HCI_SCODATA_PKT:
+                       BT_DBG("SCO packet");
+                       ll->rx_state = HCILL_W4_SCO_HDR;
+                       ll->rx_count = HCI_SCO_HDR_SIZE;
+                       type = HCI_SCODATA_PKT;
+                       break;
+
+               /* HCILL signals */
+               case HCILL_GO_TO_SLEEP_IND:
+                       BT_DBG("HCILL_GO_TO_SLEEP_IND packet");
+                       ll_device_want_to_sleep(hu);
+                       ptr++; count--;
+                       continue;
+
+               case HCILL_GO_TO_SLEEP_ACK:
+                       /* shouldn't happen */
+                       BT_ERR("received HCILL_GO_TO_SLEEP_ACK (in state %ld)", ll->hcill_state);
+                       ptr++; count--;
+                       continue;
+
+               case HCILL_WAKE_UP_IND:
+                       BT_DBG("HCILL_WAKE_UP_IND packet");
+                       ll_device_want_to_wakeup(hu);
+                       ptr++; count--;
+                       continue;
+
+               case HCILL_WAKE_UP_ACK:
+                       BT_DBG("HCILL_WAKE_UP_ACK packet");
+                       ll_device_woke_up(hu);
+                       ptr++; count--;
+                       continue;
+
+               default:
+                       BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+                       hu->hdev->stat.err_rx++;
+                       ptr++; count--;
+                       continue;
+               };
+
+               ptr++; count--;
+
+               /* Allocate packet */
+               ll->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+               if (!ll->rx_skb) {
+                       BT_ERR("Can't allocate mem for new packet");
+                       ll->rx_state = HCILL_W4_PACKET_TYPE;
+                       ll->rx_count = 0;
+                       return 0;
+               }
+
+               ll->rx_skb->dev = (void *) hu->hdev;
+               bt_cb(ll->rx_skb)->pkt_type = type;
+       }
+
+       return count;
+}
+
+static struct sk_buff *ll_dequeue(struct hci_uart *hu)
+{
+       struct ll_struct *ll = hu->priv;
+       return skb_dequeue(&ll->txq);
+}
+
+static struct hci_uart_proto llp = {
+       .id             = HCI_UART_LL,
+       .open           = ll_open,
+       .close          = ll_close,
+       .recv           = ll_recv,
+       .enqueue        = ll_enqueue,
+       .dequeue        = ll_dequeue,
+       .flush          = ll_flush,
+};
+
+int ll_init(void)
+{
+       int err = hci_uart_register_proto(&llp);
+
+       if (!err)
+               BT_INFO("HCILL protocol initialized");
+       else
+               BT_ERR("HCILL protocol registration failed");
+
+       return err;
+}
+
+int ll_deinit(void)
+{
+       return hci_uart_unregister_proto(&llp);
+}
index 1097ce7..50113db 100644 (file)
 #define HCIUARTGETDEVICE       _IOR('U', 202, int)
 
 /* UART protocols */
-#define HCI_UART_MAX_PROTO     4
+#define HCI_UART_MAX_PROTO     5
 
 #define HCI_UART_H4    0
 #define HCI_UART_BCSP  1
 #define HCI_UART_3WIRE 2
 #define HCI_UART_H4DS  3
+#define HCI_UART_LL    4
 
 struct hci_uart;
 
@@ -85,3 +86,8 @@ int h4_deinit(void);
 int bcsp_init(void);
 int bcsp_deinit(void);
 #endif
+
+#ifdef CONFIG_BT_HCIUART_LL
+int ll_init(void);
+int ll_deinit(void);
+#endif
index 6549110..bf18d75 100644 (file)
@@ -613,6 +613,10 @@ config HVC_XEN
        help
          Xen virtual console device driver
 
+config VIRTIO_CONSOLE
+       bool
+       select HVC_DRIVER
+
 config HVCS
        tristate "IBM Hypervisor Virtual Console Server support"
        depends on PPC_PSERIES
index c78ff26..07304d5 100644 (file)
@@ -42,7 +42,6 @@ obj-$(CONFIG_SYNCLINK_GT)     += synclink_gt.o
 obj-$(CONFIG_N_HDLC)           += n_hdlc.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)               += sx.o generic_serial.o
-obj-$(CONFIG_LGUEST_GUEST)     += hvc_lguest.o
 obj-$(CONFIG_RIO)              += rio/ generic_serial.o
 obj-$(CONFIG_HVC_CONSOLE)      += hvc_vio.o hvsi.o
 obj-$(CONFIG_HVC_ISERIES)      += hvc_iseries.o
@@ -50,6 +49,7 @@ obj-$(CONFIG_HVC_RTAS)                += hvc_rtas.o
 obj-$(CONFIG_HVC_BEAT)         += hvc_beat.o
 obj-$(CONFIG_HVC_DRIVER)       += hvc_console.o
 obj-$(CONFIG_HVC_XEN)          += hvc_xen.o
+obj-$(CONFIG_VIRTIO_CONSOLE)   += virtio_console.o
 obj-$(CONFIG_RAW_DRIVER)       += raw.o
 obj-$(CONFIG_SGI_SNSC)         += snsc.o snsc_event.o
 obj-$(CONFIG_MSPEC)            += mspec.o
index d1bd0f0..e4f579c 100644 (file)
@@ -1602,8 +1602,8 @@ static void cyz_handle_tx(struct cyclades_port *info,
                        info->icount.tx++;
                }
 #endif
-ztxdone:
                tty_wakeup(tty);
+ztxdone:
                /* Update tx_put */
                cy_writel(&buf_ctrl->tx_put, tx_put);
        }
diff --git a/drivers/char/hvc_lguest.c b/drivers/char/hvc_lguest.c
deleted file mode 100644 (file)
index efccb21..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*D:300
- * The Guest console driver
- *
- * This is a trivial console driver: we use lguest's DMA mechanism to send
- * bytes out, and register a DMA buffer to receive bytes in.  It is assumed to
- * be present and available from the very beginning of boot.
- *
- * Writing console drivers is one of the few remaining Dark Arts in Linux.
- * Fortunately for us, the path of virtual consoles has been well-trodden by
- * the PowerPC folks, who wrote "hvc_console.c" to generically support any
- * virtual console.  We use that infrastructure which only requires us to write
- * the basic put_chars and get_chars functions and call the right register
- * functions.
- :*/
-
-/*M:002 The console can be flooded: while the Guest is processing input the
- * Host can send more.  Buffering in the Host could alleviate this, but it is a
- * difficult problem in general. :*/
-/* Copyright (C) 2006 Rusty Russell, IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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/err.h>
-#include <linux/init.h>
-#include <linux/lguest_bus.h>
-#include <asm/paravirt.h>
-#include "hvc_console.h"
-
-/*D:340 This is our single console input buffer, with associated "struct
- * lguest_dma" referring to it.  Note the 0-terminated length array, and the
- * use of physical address for the buffer itself. */
-static char inbuf[256];
-static struct lguest_dma cons_input = { .used_len = 0,
-                                       .addr[0] = __pa(inbuf),
-                                       .len[0] = sizeof(inbuf),
-                                       .len[1] = 0 };
-
-/*D:310 The put_chars() callback is pretty straightforward.
- *
- * First we put the pointer and length in a "struct lguest_dma": we only have
- * one pointer, so we set the second length to 0.  Then we use SEND_DMA to send
- * the data to (Host) buffers attached to the console key.  Usually a device's
- * key is a physical address within the device's memory, but because the
- * console device doesn't have any associated physical memory, we use the
- * LGUEST_CONSOLE_DMA_KEY constant (aka 0). */
-static int put_chars(u32 vtermno, const char *buf, int count)
-{
-       struct lguest_dma dma;
-
-       /* FIXME: DMA buffers in a "struct lguest_dma" are not allowed
-        * to go over page boundaries.  This never seems to happen,
-        * but if it did we'd need to fix this code. */
-       dma.len[0] = count;
-       dma.len[1] = 0;
-       dma.addr[0] = __pa(buf);
-
-       lguest_send_dma(LGUEST_CONSOLE_DMA_KEY, &dma);
-       /* We're expected to return the amount of data we wrote: all of it. */
-       return count;
-}
-
-/*D:350 get_chars() is the callback from the hvc_console infrastructure when
- * an interrupt is received.
- *
- * Firstly we see if our buffer has been filled: if not, we return.  The rest
- * of the code deals with the fact that the hvc_console() infrastructure only
- * asks us for 16 bytes at a time.  We keep a "cons_offset" variable for
- * partially-read buffers. */
-static int get_chars(u32 vtermno, char *buf, int count)
-{
-       static int cons_offset;
-
-       /* Nothing left to see here... */
-       if (!cons_input.used_len)
-               return 0;
-
-       /* You want more than we have to give?  Well, try wanting less! */
-       if (cons_input.used_len - cons_offset < count)
-               count = cons_input.used_len - cons_offset;
-
-       /* Copy across to their buffer and increment offset. */
-       memcpy(buf, inbuf + cons_offset, count);
-       cons_offset += count;
-
-       /* Finished?  Zero offset, and reset cons_input so Host will use it
-        * again. */
-       if (cons_offset == cons_input.used_len) {
-               cons_offset = 0;
-               cons_input.used_len = 0;
-       }
-       return count;
-}
-/*:*/
-
-static struct hv_ops lguest_cons = {
-       .get_chars = get_chars,
-       .put_chars = put_chars,
-};
-
-/*D:320 Console drivers are initialized very early so boot messages can go
- * out.  At this stage, the console is output-only.  Our driver checks we're a
- * Guest, and if so hands hvc_instantiate() the console number (0), priority
- * (0), and the struct hv_ops containing the put_chars() function. */
-static int __init cons_init(void)
-{
-       if (strcmp(pv_info.name, "lguest") != 0)
-               return 0;
-
-       return hvc_instantiate(0, 0, &lguest_cons);
-}
-console_initcall(cons_init);
-
-/*D:370 To set up and manage our virtual console, we call hvc_alloc() and
- * stash the result in the private pointer of the "struct lguest_device".
- * Since we never remove the console device we never need this pointer again,
- * but using ->private is considered good form, and you never know who's going
- * to copy your driver.
- *
- * Once the console is set up, we bind our input buffer ready for input. */
-static int lguestcons_probe(struct lguest_device *lgdev)
-{
-       int err;
-
-       /* The first argument of hvc_alloc() is the virtual console number, so
-        * we use zero.  The second argument is the interrupt number.
-        *
-        * The third argument is a "struct hv_ops" containing the put_chars()
-        * and get_chars() pointers.  The final argument is the output buffer
-        * size: we use 256 and expect the Host to have room for us to send
-        * that much. */
-       lgdev->private = hvc_alloc(0, lgdev_irq(lgdev), &lguest_cons, 256);
-       if (IS_ERR(lgdev->private))
-               return PTR_ERR(lgdev->private);
-
-       /* We bind a single DMA buffer at key LGUEST_CONSOLE_DMA_KEY.
-        * "cons_input" is that statically-initialized global DMA buffer we saw
-        * above, and we also give the interrupt we want. */
-       err = lguest_bind_dma(LGUEST_CONSOLE_DMA_KEY, &cons_input, 1,
-                             lgdev_irq(lgdev));
-       if (err)
-               printk("lguest console: failed to bind buffer.\n");
-       return err;
-}
-/* Note the use of lgdev_irq() for the interrupt number.  We tell hvc_alloc()
- * to expect input when this interrupt is triggered, and then tell
- * lguest_bind_dma() that is the interrupt to send us when input comes in. */
-
-/*D:360 From now on the console driver follows standard Guest driver form:
- * register_lguest_driver() registers the device type and probe function, and
- * the probe function sets up the device.
- *
- * The standard "struct lguest_driver": */
-static struct lguest_driver lguestcons_drv = {
-       .name = "lguestcons",
-       .owner = THIS_MODULE,
-       .device_type = LGUEST_DEVICE_T_CONSOLE,
-       .probe = lguestcons_probe,
-};
-
-/* The standard init function */
-static int __init hvc_lguest_init(void)
-{
-       return register_lguest_driver(&lguestcons_drv);
-}
-module_init(hvc_lguest_init);
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
new file mode 100644 (file)
index 0000000..100e8a2
--- /dev/null
@@ -0,0 +1,225 @@
+/*D:300
+ * The Guest console driver
+ *
+ * Writing console drivers is one of the few remaining Dark Arts in Linux.
+ * Fortunately for us, the path of virtual consoles has been well-trodden by
+ * the PowerPC folks, who wrote "hvc_console.c" to generically support any
+ * virtual console.  We use that infrastructure which only requires us to write
+ * the basic put_chars and get_chars functions and call the right register
+ * functions.
+ :*/
+
+/*M:002 The console can be flooded: while the Guest is processing input the
+ * Host can send more.  Buffering in the Host could alleviate this, but it is a
+ * difficult problem in general. :*/
+/* Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/err.h>
+#include <linux/init.h>
+#include <linux/virtio.h>
+#include <linux/virtio_console.h>
+#include "hvc_console.h"
+
+/*D:340 These represent our input and output console queues, and the virtio
+ * operations for them. */
+static struct virtqueue *in_vq, *out_vq;
+static struct virtio_device *vdev;
+
+/* This is our input buffer, and how much data is left in it. */
+static unsigned int in_len;
+static char *in, *inbuf;
+
+/* The operations for our console. */
+static struct hv_ops virtio_cons;
+
+/*D:310 The put_chars() callback is pretty straightforward.
+ *
+ * We turn the characters into a scatter-gather list, add it to the output
+ * queue and then kick the Host.  Then we sit here waiting for it to finish:
+ * inefficient in theory, but in practice implementations will do it
+ * immediately (lguest's Launcher does). */
+static int put_chars(u32 vtermno, const char *buf, int count)
+{
+       struct scatterlist sg[1];
+       unsigned int len;
+
+       /* This is a convenient routine to initialize a single-elem sg list */
+       sg_init_one(sg, buf, count);
+
+       /* add_buf wants a token to identify this buffer: we hand it any
+        * non-NULL pointer, since there's only ever one buffer. */
+       if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) == 0) {
+               /* Tell Host to go! */
+               out_vq->vq_ops->kick(out_vq);
+               /* Chill out until it's done with the buffer. */
+               while (!out_vq->vq_ops->get_buf(out_vq, &len))
+                       cpu_relax();
+       }
+
+       /* We're expected to return the amount of data we wrote: all of it. */
+       return count;
+}
+
+/* Create a scatter-gather list representing our input buffer and put it in the
+ * queue. */
+static void add_inbuf(void)
+{
+       struct scatterlist sg[1];
+       sg_init_one(sg, inbuf, PAGE_SIZE);
+
+       /* We should always be able to add one buffer to an empty queue. */
+       if (in_vq->vq_ops->add_buf(in_vq, sg, 0, 1, inbuf) != 0)
+               BUG();
+       in_vq->vq_ops->kick(in_vq);
+}
+
+/*D:350 get_chars() is the callback from the hvc_console infrastructure when
+ * an interrupt is received.
+ *
+ * Most of the code deals with the fact that the hvc_console() infrastructure
+ * only asks us for 16 bytes at a time.  We keep in_offset and in_used fields
+ * for partially-filled buffers. */
+static int get_chars(u32 vtermno, char *buf, int count)
+{
+       /* If we don't have an input queue yet, we can't get input. */
+       BUG_ON(!in_vq);
+
+       /* No buffer?  Try to get one. */
+       if (!in_len) {
+               in = in_vq->vq_ops->get_buf(in_vq, &in_len);
+               if (!in)
+                       return 0;
+       }
+
+       /* You want more than we have to give?  Well, try wanting less! */
+       if (in_len < count)
+               count = in_len;
+
+       /* Copy across to their buffer and increment offset. */
+       memcpy(buf, in, count);
+       in += count;
+       in_len -= count;
+
+       /* Finished?  Re-register buffer so Host will use it again. */
+       if (in_len == 0)
+               add_inbuf();
+
+       return count;
+}
+/*:*/
+
+/*D:320 Console drivers are initialized very early so boot messages can go out,
+ * so we do things slightly differently from the generic virtio initialization
+ * of the net and block drivers.
+ *
+ * At this stage, the console is output-only.  It's too early to set up a
+ * virtqueue, so we let the drivers do some boutique early-output thing. */
+int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
+{
+       virtio_cons.put_chars = put_chars;
+       return hvc_instantiate(0, 0, &virtio_cons);
+}
+
+/*D:370 Once we're further in boot, we get probed like any other virtio device.
+ * At this stage we set up the output virtqueue.
+ *
+ * To set up and manage our virtual console, we call hvc_alloc().  Since we
+ * never remove the console device we never need this pointer again.
+ *
+ * Finally we put our input buffer in the input queue, ready to receive. */
+static int virtcons_probe(struct virtio_device *dev)
+{
+       int err;
+       struct hvc_struct *hvc;
+
+       vdev = dev;
+
+       /* This is the scratch page we use to receive console input */
+       inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!inbuf) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Find the input queue. */
+       /* FIXME: This is why we want to wean off hvc: we do nothing
+        * when input comes in. */
+       in_vq = vdev->config->find_vq(vdev, NULL);
+       if (IS_ERR(in_vq)) {
+               err = PTR_ERR(in_vq);
+               goto free;
+       }
+
+       out_vq = vdev->config->find_vq(vdev, NULL);
+       if (IS_ERR(out_vq)) {
+               err = PTR_ERR(out_vq);
+               goto free_in_vq;
+       }
+
+       /* Start using the new console output. */
+       virtio_cons.get_chars = get_chars;
+       virtio_cons.put_chars = put_chars;
+
+       /* The first argument of hvc_alloc() is the virtual console number, so
+        * we use zero.  The second argument is the interrupt number; we
+        * currently leave this as zero: it would be better not to use the
+        * hvc mechanism and fix this (FIXME!).
+        *
+        * The third argument is a "struct hv_ops" containing the put_chars()
+        * and get_chars() pointers.  The final argument is the output buffer
+        * size: we can do any size, so we put PAGE_SIZE here. */
+       hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE);
+       if (IS_ERR(hvc)) {
+               err = PTR_ERR(hvc);
+               goto free_out_vq;
+       }
+
+       /* Register the input buffer the first time. */
+       add_inbuf();
+       return 0;
+
+free_out_vq:
+       vdev->config->del_vq(out_vq);
+free_in_vq:
+       vdev->config->del_vq(in_vq);
+free:
+       kfree(inbuf);
+fail:
+       return err;
+}
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static struct virtio_driver virtio_console = {
+       .driver.name =  KBUILD_MODNAME,
+       .driver.owner = THIS_MODULE,
+       .id_table =     id_table,
+       .probe =        virtcons_probe,
+};
+
+static int __init init(void)
+{
+       return register_virtio_driver(&virtio_console);
+}
+module_init(init);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio console driver");
+MODULE_LICENSE("GPL");
index 2f307c4..6758832 100644 (file)
@@ -606,7 +606,7 @@ static int
 at_context_queue_packet(struct context *ctx, struct fw_packet *packet)
 {
        struct fw_ohci *ohci = ctx->ohci;
-       dma_addr_t d_bus, payload_bus;
+       dma_addr_t d_bus, uninitialized_var(payload_bus);
        struct driver_data *driver_data;
        struct descriptor *d, *last;
        __le32 *header;
@@ -1459,7 +1459,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
        /* FIXME: We need a fallback for pre 1.1 OHCI. */
        if (callback == handle_ir_dualbuffer_packet &&
            ohci->version < OHCI_VERSION_1_1)
-               return ERR_PTR(-EINVAL);
+               return ERR_PTR(-ENOSYS);
 
        spin_lock_irqsave(&ohci->lock, flags);
        index = ffs(*mask) - 1;
@@ -1778,7 +1778,7 @@ ohci_queue_iso(struct fw_iso_context *base,
                                                         buffer, payload);
        else
                /* FIXME: Implement fallback for OHCI 1.0 controllers. */
-               return -EINVAL;
+               return -ENOSYS;
 }
 
 static const struct fw_card_driver ohci_driver = {
@@ -1898,7 +1898,12 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
        ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
        fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
                  dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff);
-
+       if (ohci->version < OHCI_VERSION_1_1) {
+               fw_notify("    Isochronous I/O is not yet implemented for "
+                         "OHCI 1.0 chips.\n");
+               fw_notify("    Cameras, audio devices etc. won't work on "
+                         "this controller with this driver version.\n");
+       }
        return 0;
 
  fail_self_id:
index ff20377..e196aef 100644 (file)
@@ -935,11 +935,11 @@ static int cris_ide_build_dmatable (ide_drive_t *drive)
                 * than two possibly non-adjacent physical 4kB pages.
                 */
                /* group sequential buffers into one large buffer */
-               addr = page_to_phys(sg->page) + sg->offset;
+               addr = sg_phys(sg);
                size = sg_dma_len(sg);
                while (--i) {
                        sg = sg_next(sg);
-                       if ((addr + size) != page_to_phys(sg->page) + sg->offset)
+                       if ((addr + size) != sg_phys(sg))
                                break;
                        size += sg_dma_len(sg);
                }
index d5146c5..6a6f2e0 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/spinlock.h>
 #include <linux/kmod.h>
 #include <linux/pci.h>
+#include <linux/scatterlist.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -1317,12 +1318,14 @@ static int hwif_init(ide_hwif_t *hwif)
        if (!hwif->sg_max_nents)
                hwif->sg_max_nents = PRD_ENTRIES;
 
-       hwif->sg_table = kzalloc(sizeof(struct scatterlist)*hwif->sg_max_nents,
+       hwif->sg_table = kmalloc(sizeof(struct scatterlist)*hwif->sg_max_nents,
                                 GFP_KERNEL);
        if (!hwif->sg_table) {
                printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name);
                goto out;
        }
+
+       sg_init_table(hwif->sg_table, hwif->sg_max_nents);
        
        if (init_irq(hwif) == 0)
                goto done;
index 73ef6bf..d066546 100644 (file)
@@ -261,7 +261,7 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
                hwif->cursg = sg;
        }
 
-       page = cursg->page;
+       page = sg_page(cursg);
        offset = cursg->offset + hwif->cursg_ofs * SECTOR_SIZE;
 
        /* get the current page and offset */
index 1de5856..a4ce3ba 100644 (file)
@@ -276,8 +276,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
 
                        if (iswrite) {
                                if(!put_source_flags(ahwif->tx_chan, 
-                                                    (void*)(page_address(sg->page) 
-                                                            + sg->offset), 
+                                                    (void*) sg_virt(sg),
                                                     tc, flags)) { 
                                        printk(KERN_ERR "%s failed %d\n", 
                                               __FUNCTION__, __LINE__);
@@ -285,8 +284,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
                        } else 
                        {
                                if(!put_dest_flags(ahwif->rx_chan, 
-                                                  (void*)(page_address(sg->page) 
-                                                          + sg->offset), 
+                                                  (void*) sg_virt(sg),
                                                   tc, flags)) { 
                                        printk(KERN_ERR "%s failed %d\n", 
                                               __FUNCTION__, __LINE__);
index 45d6055..3051e31 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 #include "dma.h"
 
@@ -111,7 +111,7 @@ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
                unsigned long va =
                    (unsigned long)dma->kvirt + (i << PAGE_SHIFT);
 
-               dma->sglist[i].page = vmalloc_to_page((void *)va);
+               sg_set_page(&dma->sglist[i], vmalloc_to_page((void *)va));
                dma->sglist[i].length = PAGE_SIZE;
        }
 
index 1b353b9..d5dfe11 100644 (file)
@@ -1466,7 +1466,7 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
                cmd->dma_size = sgpnt[0].length;
                cmd->dma_type = CMD_DMA_PAGE;
                cmd->cmd_dma = dma_map_page(hi->host->device.parent,
-                                           sgpnt[0].page, sgpnt[0].offset,
+                                           sg_page(&sgpnt[0]), sgpnt[0].offset,
                                            cmd->dma_size, cmd->dma_dir);
 
                orb->data_descriptor_lo = cmd->cmd_dma;
index d08fb30..0751697 100644 (file)
@@ -114,13 +114,16 @@ struct rdma_id_private {
 
        struct rdma_bind_list   *bind_list;
        struct hlist_node       node;
-       struct list_head        list;
-       struct list_head        listen_list;
+       struct list_head        list; /* listen_any_list or cma_device.list */
+       struct list_head        listen_list; /* per device listens */
        struct cma_device       *cma_dev;
        struct list_head        mc_list;
 
+       int                     internal_id;
        enum cma_state          state;
        spinlock_t              lock;
+       struct mutex            qp_mutex;
+
        struct completion       comp;
        atomic_t                refcount;
        wait_queue_head_t       wait_remove;
@@ -389,6 +392,7 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
        id_priv->id.event_handler = event_handler;
        id_priv->id.ps = ps;
        spin_lock_init(&id_priv->lock);
+       mutex_init(&id_priv->qp_mutex);
        init_completion(&id_priv->comp);
        atomic_set(&id_priv->refcount, 1);
        init_waitqueue_head(&id_priv->wait_remove);
@@ -474,61 +478,86 @@ EXPORT_SYMBOL(rdma_create_qp);
 
 void rdma_destroy_qp(struct rdma_cm_id *id)
 {
-       ib_destroy_qp(id->qp);
+       struct rdma_id_private *id_priv;
+
+       id_priv = container_of(id, struct rdma_id_private, id);
+       mutex_lock(&id_priv->qp_mutex);
+       ib_destroy_qp(id_priv->id.qp);
+       id_priv->id.qp = NULL;
+       mutex_unlock(&id_priv->qp_mutex);
 }
 EXPORT_SYMBOL(rdma_destroy_qp);
 
-static int cma_modify_qp_rtr(struct rdma_cm_id *id)
+static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
 {
        struct ib_qp_attr qp_attr;
        int qp_attr_mask, ret;
 
-       if (!id->qp)
-               return 0;
+       mutex_lock(&id_priv->qp_mutex);
+       if (!id_priv->id.qp) {
+               ret = 0;
+               goto out;
+       }
 
        /* Need to update QP attributes from default values. */
        qp_attr.qp_state = IB_QPS_INIT;
-       ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
+       ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
        if (ret)
-               return ret;
+               goto out;
 
-       ret = ib_modify_qp(id->qp, &qp_attr, qp_attr_mask);
+       ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
        if (ret)
-               return ret;
+               goto out;
 
        qp_attr.qp_state = IB_QPS_RTR;
-       ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
+       ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
        if (ret)
-               return ret;
+               goto out;
 
-       return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask);
+       ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
+out:
+       mutex_unlock(&id_priv->qp_mutex);
+       return ret;
 }
 
-static int cma_modify_qp_rts(struct rdma_cm_id *id)
+static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
 {
        struct ib_qp_attr qp_attr;
        int qp_attr_mask, ret;
 
-       if (!id->qp)
-               return 0;
+       mutex_lock(&id_priv->qp_mutex);
+       if (!id_priv->id.qp) {
+               ret = 0;
+               goto out;
+       }
 
        qp_attr.qp_state = IB_QPS_RTS;
-       ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
+       ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
        if (ret)
-               return ret;
+               goto out;
 
-       return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask);
+       ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
+out:
+       mutex_unlock(&id_priv->qp_mutex);
+       return ret;
 }
 
-static int cma_modify_qp_err(struct rdma_cm_id *id)
+static int cma_modify_qp_err(struct rdma_id_private *id_priv)
 {
        struct ib_qp_attr qp_attr;
+       int ret;
 
-       if (!id->qp)
-               return 0;
+       mutex_lock(&id_priv->qp_mutex);
+       if (!id_priv->id.qp) {
+               ret = 0;
+               goto out;
+       }
 
        qp_attr.qp_state = IB_QPS_ERR;
-       return ib_modify_qp(id->qp, &qp_attr, IB_QP_STATE);
+       ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE);
+out:
+       mutex_unlock(&id_priv->qp_mutex);
+       return ret;
 }
 
 static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
@@ -717,50 +746,27 @@ static void cma_cancel_route(struct rdma_id_private *id_priv)
        }
 }
 
-static inline int cma_internal_listen(struct rdma_id_private *id_priv)
-{
-       return (id_priv->state == CMA_LISTEN) && id_priv->cma_dev &&
-              cma_any_addr(&id_priv->id.route.addr.src_addr);
-}
-
-static void cma_destroy_listen(struct rdma_id_private *id_priv)
-{
-       cma_exch(id_priv, CMA_DESTROYING);
-
-       if (id_priv->cma_dev) {
-               switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
-               case RDMA_TRANSPORT_IB:
-                       if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
-                               ib_destroy_cm_id(id_priv->cm_id.ib);
-                       break;
-               case RDMA_TRANSPORT_IWARP:
-                       if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw))
-                               iw_destroy_cm_id(id_priv->cm_id.iw);
-                       break;
-               default:
-                       break;
-               }
-               cma_detach_from_dev(id_priv);
-       }
-       list_del(&id_priv->listen_list);
-
-       cma_deref_id(id_priv);
-       wait_for_completion(&id_priv->comp);
-
-       kfree(id_priv);
-}
-
 static void cma_cancel_listens(struct rdma_id_private *id_priv)
 {
        struct rdma_id_private *dev_id_priv;
 
+       /*
+        * Remove from listen_any_list to prevent added devices from spawning
+        * additional listen requests.
+        */
        mutex_lock(&lock);
        list_del(&id_priv->list);
 
        while (!list_empty(&id_priv->listen_list)) {
                dev_id_priv = list_entry(id_priv->listen_list.next,
                                         struct rdma_id_private, listen_list);
-               cma_destroy_listen(dev_id_priv);
+               /* sync with device removal to avoid duplicate destruction */
+               list_del_init(&dev_id_priv->list);
+               list_del(&dev_id_priv->listen_list);
+               mutex_unlock(&lock);
+
+               rdma_destroy_id(&dev_id_priv->id);
+               mutex_lock(&lock);
        }
        mutex_unlock(&lock);
 }
@@ -848,6 +854,9 @@ void rdma_destroy_id(struct rdma_cm_id *id)
        cma_deref_id(id_priv);
        wait_for_completion(&id_priv->comp);
 
+       if (id_priv->internal_id)
+               cma_deref_id(id_priv->id.context);
+
        kfree(id_priv->id.route.path_rec);
        kfree(id_priv);
 }
@@ -857,11 +866,11 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
 {
        int ret;
 
-       ret = cma_modify_qp_rtr(&id_priv->id);
+       ret = cma_modify_qp_rtr(id_priv);
        if (ret)
                goto reject;
 
-       ret = cma_modify_qp_rts(&id_priv->id);
+       ret = cma_modify_qp_rts(id_priv);
        if (ret)
                goto reject;
 
@@ -871,7 +880,7 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
 
        return 0;
 reject:
-       cma_modify_qp_err(&id_priv->id);
+       cma_modify_qp_err(id_priv);
        ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
                       NULL, 0, NULL, 0);
        return ret;
@@ -947,7 +956,7 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
                /* ignore event */
                goto out;
        case IB_CM_REJ_RECEIVED:
-               cma_modify_qp_err(&id_priv->id);
+               cma_modify_qp_err(id_priv);
                event.status = ib_event->param.rej_rcvd.reason;
                event.event = RDMA_CM_EVENT_REJECTED;
                event.param.conn.private_data = ib_event->private_data;
@@ -1404,14 +1413,13 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
 
        cma_attach_to_dev(dev_id_priv, cma_dev);
        list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
+       atomic_inc(&id_priv->refcount);
+       dev_id_priv->internal_id = 1;
 
        ret = rdma_listen(id, id_priv->backlog);
        if (ret)
-               goto err;
-
-       return;
-err:
-       cma_destroy_listen(dev_id_priv);
+               printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, "
+                      "listening on device %s", ret, cma_dev->device->name);
 }
 
 static void cma_listen_on_all(struct rdma_id_private *id_priv)
@@ -2264,7 +2272,7 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
        sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
        cm_id->remote_addr = *sin;
 
-       ret = cma_modify_qp_rtr(&id_priv->id);
+       ret = cma_modify_qp_rtr(id_priv);
        if (ret)
                goto out;
 
@@ -2331,7 +2339,7 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
        int qp_attr_mask, ret;
 
        if (id_priv->id.qp) {
-               ret = cma_modify_qp_rtr(&id_priv->id);
+               ret = cma_modify_qp_rtr(id_priv);
                if (ret)
                        goto out;
 
@@ -2370,7 +2378,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
        struct iw_cm_conn_param iw_param;
        int ret;
 
-       ret = cma_modify_qp_rtr(&id_priv->id);
+       ret = cma_modify_qp_rtr(id_priv);
        if (ret)
                return ret;
 
@@ -2442,7 +2450,7 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
 
        return 0;
 reject:
-       cma_modify_qp_err(id);
+       cma_modify_qp_err(id_priv);
        rdma_reject(id, NULL, 0);
        return ret;
 }
@@ -2512,7 +2520,7 @@ int rdma_disconnect(struct rdma_cm_id *id)
 
        switch (rdma_node_get_transport(id->device->node_type)) {
        case RDMA_TRANSPORT_IB:
-               ret = cma_modify_qp_err(id);
+               ret = cma_modify_qp_err(id_priv);
                if (ret)
                        goto out;
                /* Initiate or respond to a disconnect. */
@@ -2543,9 +2551,11 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
            cma_disable_remove(id_priv, CMA_ADDR_RESOLVED))
                return 0;
 
+       mutex_lock(&id_priv->qp_mutex);
        if (!status && id_priv->id.qp)
                status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
                                         multicast->rec.mlid);
+       mutex_unlock(&id_priv->qp_mutex);
 
        memset(&event, 0, sizeof event);
        event.status = status;
@@ -2757,16 +2767,12 @@ static void cma_process_remove(struct cma_device *cma_dev)
                id_priv = list_entry(cma_dev->id_list.next,
                                     struct rdma_id_private, list);
 
-               if (cma_internal_listen(id_priv)) {
-                       cma_destroy_listen(id_priv);
-                       continue;
-               }
-
+               list_del(&id_priv->listen_list);
                list_del_init(&id_priv->list);
                atomic_inc(&id_priv->refcount);
                mutex_unlock(&lock);
 
-               ret = cma_remove_id_dev(id_priv);
+               ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv);
                cma_deref_id(id_priv);
                if (ret)
                        rdma_destroy_id(&id_priv->id);
index 2f54e29..14159ff 100644 (file)
@@ -55,9 +55,11 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
                ib_dma_unmap_sg(dev, chunk->page_list,
                                chunk->nents, DMA_BIDIRECTIONAL);
                for (i = 0; i < chunk->nents; ++i) {
+                       struct page *page = sg_page(&chunk->page_list[i]);
+
                        if (umem->writable && dirty)
-                               set_page_dirty_lock(chunk->page_list[i].page);
-                       put_page(chunk->page_list[i].page);
+                               set_page_dirty_lock(page);
+                       put_page(page);
                }
 
                kfree(chunk);
@@ -164,11 +166,12 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
                        }
 
                        chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK);
+                       sg_init_table(chunk->page_list, chunk->nents);
                        for (i = 0; i < chunk->nents; ++i) {
                                if (vma_list &&
                                    !is_vm_hugetlb_page(vma_list[i + off]))
                                        umem->hugetlb = 0;
-                               chunk->page_list[i].page   = page_list[i + off];
+                               sg_set_page(&chunk->page_list[i], page_list[i + off]);
                                chunk->page_list[i].offset = 0;
                                chunk->page_list[i].length = PAGE_SIZE;
                        }
@@ -179,7 +182,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
                                                    DMA_BIDIRECTIONAL);
                        if (chunk->nmap <= 0) {
                                for (i = 0; i < chunk->nents; ++i)
-                                       put_page(chunk->page_list[i].page);
+                                       put_page(sg_page(&chunk->page_list[i]));
                                kfree(chunk);
 
                                ret = -ENOMEM;
index 01d7008..495c803 100644 (file)
@@ -147,8 +147,12 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
 
        spin_lock(&ib_uverbs_idr_lock);
        uobj = idr_find(idr, id);
-       if (uobj)
-               kref_get(&uobj->ref);
+       if (uobj) {
+               if (uobj->context == context)
+                       kref_get(&uobj->ref);
+               else
+                       uobj = NULL;
+       }
        spin_unlock(&ib_uverbs_idr_lock);
 
        return uobj;
index 3f2d68c..2d660ae 100644 (file)
@@ -323,7 +323,6 @@ extern int ehca_static_rate;
 extern int ehca_port_act_time;
 extern int ehca_use_hp_mr;
 extern int ehca_scaling_code;
-extern int ehca_mr_largepage;
 
 struct ipzu_queue_resp {
        u32 qe_size;      /* queue entry size */
index 4aa3ffa..15806d1 100644 (file)
@@ -77,6 +77,7 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
        }
 
        memset(props, 0, sizeof(struct ib_device_attr));
+       props->page_size_cap   = shca->hca_cap_mr_pgsize;
        props->fw_ver          = rblock->hw_ver;
        props->max_mr_size     = rblock->max_mr_size;
        props->vendor_id       = rblock->vendor_id >> 8;
index 7a7dab8..c6cd38c 100644 (file)
@@ -65,7 +65,7 @@ int ehca_port_act_time = 30;
 int ehca_poll_all_eqs  = 1;
 int ehca_static_rate   = -1;
 int ehca_scaling_code  = 0;
-int ehca_mr_largepage  = 0;
+int ehca_mr_largepage  = 1;
 
 module_param_named(open_aqp1,     ehca_open_aqp1,     int, S_IRUGO);
 module_param_named(debug_level,   ehca_debug_level,   int, S_IRUGO);
@@ -260,13 +260,20 @@ static struct cap_descr {
        { HCA_CAP_MINI_QP, "HCA_CAP_MINI_QP" },
 };
 
-int ehca_sense_attributes(struct ehca_shca *shca)
+static int ehca_sense_attributes(struct ehca_shca *shca)
 {
        int i, ret = 0;
        u64 h_ret;
        struct hipz_query_hca *rblock;
        struct hipz_query_port *port;
 
+       static const u32 pgsize_map[] = {
+               HCA_CAP_MR_PGSIZE_4K,  0x1000,
+               HCA_CAP_MR_PGSIZE_64K, 0x10000,
+               HCA_CAP_MR_PGSIZE_1M,  0x100000,
+               HCA_CAP_MR_PGSIZE_16M, 0x1000000,
+       };
+
        rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
        if (!rblock) {
                ehca_gen_err("Cannot allocate rblock memory.");
@@ -329,8 +336,15 @@ int ehca_sense_attributes(struct ehca_shca *shca)
                if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap))
                        ehca_gen_dbg("   %s", hca_cap_descr[i].descr);
 
-       shca->hca_cap_mr_pgsize = rblock->memory_page_size_supported;
+       /* translate supported MR page sizes; always support 4K */
+       shca->hca_cap_mr_pgsize = EHCA_PAGESIZE;
+       if (ehca_mr_largepage) { /* support extra sizes only if enabled */
+               for (i = 0; i < ARRAY_SIZE(pgsize_map); i += 2)
+                       if (rblock->memory_page_size_supported & pgsize_map[i])
+                               shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];
+       }
 
+       /* query max MTU from first port -- it's the same for all ports */
        port = (struct hipz_query_port *)rblock;
        h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
        if (h_ret != H_SUCCESS) {
index da88738..e239bbf 100644 (file)
@@ -72,24 +72,14 @@ enum ehca_mr_pgsize {
 
 static u32 ehca_encode_hwpage_size(u32 pgsize)
 {
-       u32 idx = 0;
-       pgsize >>= 12;
-       /*
-        * map mr page size into hw code:
-        * 0, 1, 2, 3 for 4K, 64K, 1M, 64M
-        */
-       while (!(pgsize & 1)) {
-               idx++;
-               pgsize >>= 4;
-       }
-       return idx;
+       int log = ilog2(pgsize);
+       WARN_ON(log < 12 || log > 24 || log & 3);
+       return (log - 12) / 4;
 }
 
 static u64 ehca_get_max_hwpage_size(struct ehca_shca *shca)
 {
-       if (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)
-               return EHCA_MR_PGSIZE16M;
-       return EHCA_MR_PGSIZE4K;
+       return 1UL << ilog2(shca->hca_cap_mr_pgsize);
 }
 
 static struct ehca_mr *ehca_mr_new(void)
@@ -259,7 +249,7 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
                pginfo.u.phy.num_phys_buf = num_phys_buf;
                pginfo.u.phy.phys_buf_array = phys_buf_array;
                pginfo.next_hwpage =
-                       ((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
+                       ((u64)iova_start & ~PAGE_MASK) / hw_pgsize;
 
                ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
                                  e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
@@ -296,7 +286,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
                container_of(pd->device, struct ehca_shca, ib_device);
        struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
        struct ehca_mr_pginfo pginfo;
-       int ret;
+       int ret, page_shift;
        u32 num_kpages;
        u32 num_hwpages;
        u64 hwpage_size;
@@ -351,19 +341,20 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
        /* determine number of MR pages */
        num_kpages = NUM_CHUNKS((virt % PAGE_SIZE) + length, PAGE_SIZE);
        /* select proper hw_pgsize */
-       if (ehca_mr_largepage &&
-           (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)) {
-               int page_shift = PAGE_SHIFT;
-               if (e_mr->umem->hugetlb) {
-                       /* determine page_shift, clamp between 4K and 16M */
-                       page_shift = (fls64(length - 1) + 3) & ~3;
-                       page_shift = min(max(page_shift, EHCA_MR_PGSHIFT4K),
-                                        EHCA_MR_PGSHIFT16M);
-               }
-               hwpage_size = 1UL << page_shift;
-       } else
-               hwpage_size = EHCA_MR_PGSIZE4K; /* ehca1 only supports 4k */
-       ehca_dbg(pd->device, "hwpage_size=%lx", hwpage_size);
+       page_shift = PAGE_SHIFT;
+       if (e_mr->umem->hugetlb) {
+               /* determine page_shift, clamp between 4K and 16M */
+               page_shift = (fls64(length - 1) + 3) & ~3;
+               page_shift = min(max(page_shift, EHCA_MR_PGSHIFT4K),
+                                EHCA_MR_PGSHIFT16M);
+       }
+       hwpage_size = 1UL << page_shift;
+
+       /* now that we have the desired page size, shift until it's
+        * supported, too. 4K is always supported, so this terminates.
+        */
+       while (!(hwpage_size & shca->hca_cap_mr_pgsize))
+               hwpage_size >>= 4;
 
 reg_user_mr_fallback:
        num_hwpages = NUM_CHUNKS((virt % hwpage_size) + length, hwpage_size);
@@ -547,7 +538,7 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
                pginfo.u.phy.num_phys_buf = num_phys_buf;
                pginfo.u.phy.phys_buf_array = phys_buf_array;
                pginfo.next_hwpage =
-                       ((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
+                       ((u64)iova_start & ~PAGE_MASK) / hw_pgsize;
        }
        if (mr_rereg_mask & IB_MR_REREG_ACCESS)
                new_acl = mr_access_flags;
@@ -809,8 +800,9 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
                ib_fmr = ERR_PTR(-EINVAL);
                goto alloc_fmr_exit0;
        }
-       hw_pgsize = ehca_get_max_hwpage_size(shca);
-       if ((1 << fmr_attr->page_shift) != hw_pgsize) {
+
+       hw_pgsize = 1 << fmr_attr->page_shift;
+       if (!(hw_pgsize & shca->hca_cap_mr_pgsize)) {
                ehca_err(pd->device, "unsupported fmr_attr->page_shift=%x",
                         fmr_attr->page_shift);
                ib_fmr = ERR_PTR(-EINVAL);
@@ -826,6 +818,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
 
        /* register MR on HCA */
        memset(&pginfo, 0, sizeof(pginfo));
+       pginfo.hwpage_size = hw_pgsize;
        /*
         * pginfo.num_hwpages==0, ie register_rpages() will not be called
         * but deferred to map_phys_fmr()
@@ -1776,7 +1769,7 @@ static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
        list_for_each_entry_continue(
                chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
                for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
-                       pgaddr = page_to_pfn(chunk->page_list[i].page)
+                       pgaddr = page_to_pfn(sg_page(&chunk->page_list[i]))
                                << PAGE_SHIFT ;
                        *kpage = phys_to_abs(pgaddr +
                                             (pginfo->next_hwpage *
@@ -1832,7 +1825,7 @@ static int ehca_check_kpages_per_ate(struct scatterlist *page_list,
 {
        int t;
        for (t = start_idx; t <= end_idx; t++) {
-               u64 pgaddr = page_to_pfn(page_list[t].page) << PAGE_SHIFT;
+               u64 pgaddr = page_to_pfn(sg_page(&page_list[t])) << PAGE_SHIFT;
                ehca_gen_dbg("chunk_page=%lx value=%016lx", pgaddr,
                             *(u64 *)abs_to_virt(phys_to_abs(pgaddr)));
                if (pgaddr - PAGE_SIZE != *prev_pgaddr) {
@@ -1867,7 +1860,7 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
                chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
                for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
                        if (nr_kpages == kpages_per_hwpage) {
-                               pgaddr = ( page_to_pfn(chunk->page_list[i].page)
+                               pgaddr = ( page_to_pfn(sg_page(&chunk->page_list[i]))
                                           << PAGE_SHIFT );
                                *kpage = phys_to_abs(pgaddr);
                                if ( !(*kpage) ) {
index e2bd62b..de18264 100644 (file)
@@ -451,7 +451,6 @@ static struct ehca_qp *internal_create_qp(
                has_srq = 1;
                parms.ext_type = EQPT_SRQBASE;
                parms.srq_qpn = my_srq->real_qp_num;
-               parms.srq_token = my_srq->token;
        }
 
        if (is_llqp && has_srq) {
@@ -583,6 +582,9 @@ static struct ehca_qp *internal_create_qp(
                goto create_qp_exit1;
        }
 
+       if (has_srq)
+               parms.srq_token = my_qp->token;
+
        parms.servicetype = ibqptype2servicetype(qp_type);
        if (parms.servicetype < 0) {
                ret = -EINVAL;
index 22709a4..e90a0ea 100644 (file)
@@ -108,7 +108,7 @@ static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sgl,
        BUG_ON(!valid_dma_direction(direction));
 
        for_each_sg(sgl, sg, nents, i) {
-               addr = (u64) page_address(sg->page);
+               addr = (u64) page_address(sg_page(sg));
                /* TODO: handle highmem pages */
                if (!addr) {
                        ret = 0;
@@ -127,7 +127,7 @@ static void ipath_unmap_sg(struct ib_device *dev,
 
 static u64 ipath_sg_dma_address(struct ib_device *dev, struct scatterlist *sg)
 {
-       u64 addr = (u64) page_address(sg->page);
+       u64 addr = (u64) page_address(sg_page(sg));
 
        if (addr)
                addr += sg->offset;
index e442470..db4ba92 100644 (file)
@@ -225,7 +225,7 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
                for (i = 0; i < chunk->nents; i++) {
                        void *vaddr;
 
-                       vaddr = page_address(chunk->page_list[i].page);
+                       vaddr = page_address(sg_page(&chunk->page_list[i]));
                        if (!vaddr) {
                                ret = ERR_PTR(-EINVAL);
                                goto bail;
index 31a480e..6b33224 100644 (file)
@@ -63,6 +63,10 @@ struct mlx4_ib_sqp {
        u8                      header_buf[MLX4_IB_UD_HEADER_SIZE];
 };
 
+enum {
+       MLX4_IB_MIN_SQ_STRIDE = 6
+};
+
 static const __be32 mlx4_ib_opcode[] = {
        [IB_WR_SEND]                    = __constant_cpu_to_be32(MLX4_OPCODE_SEND),
        [IB_WR_SEND_WITH_IMM]           = __constant_cpu_to_be32(MLX4_OPCODE_SEND_IMM),
@@ -285,9 +289,17 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
        return 0;
 }
 
-static int set_user_sq_size(struct mlx4_ib_qp *qp,
+static int set_user_sq_size(struct mlx4_ib_dev *dev,
+                           struct mlx4_ib_qp *qp,
                            struct mlx4_ib_create_qp *ucmd)
 {
+       /* Sanity check SQ size before proceeding */
+       if ((1 << ucmd->log_sq_bb_count) > dev->dev->caps.max_wqes       ||
+           ucmd->log_sq_stride >
+               ilog2(roundup_pow_of_two(dev->dev->caps.max_sq_desc_sz)) ||
+           ucmd->log_sq_stride < MLX4_IB_MIN_SQ_STRIDE)
+               return -EINVAL;
+
        qp->sq.wqe_cnt   = 1 << ucmd->log_sq_bb_count;
        qp->sq.wqe_shift = ucmd->log_sq_stride;
 
@@ -330,7 +342,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
 
                qp->sq_no_prefetch = ucmd.sq_no_prefetch;
 
-               err = set_user_sq_size(qp, &ucmd);
+               err = set_user_sq_size(dev, qp, &ucmd);
                if (err)
                        goto err;
 
index be6e1e0..6bd9f13 100644 (file)
@@ -204,16 +204,11 @@ static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
 static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq,
                                     int incr)
 {
-       __be32 doorbell[2];
-
        if (mthca_is_memfree(dev)) {
                *cq->set_ci_db = cpu_to_be32(cq->cons_index);
                wmb();
        } else {
-               doorbell[0] = cpu_to_be32(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn);
-               doorbell[1] = cpu_to_be32(incr - 1);
-
-               mthca_write64(doorbell,
+               mthca_write64(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn, incr - 1,
                              dev->kar + MTHCA_CQ_DOORBELL,
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
                /*
@@ -731,17 +726,12 @@ repoll:
 
 int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags)
 {
-       __be32 doorbell[2];
+       u32 dbhi = ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
+                   MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
+                   MTHCA_TAVOR_CQ_DB_REQ_NOT) |
+               to_mcq(cq)->cqn;
 
-       doorbell[0] = cpu_to_be32(((flags & IB_CQ_SOLICITED_MASK) ==
-                                  IB_CQ_SOLICITED ?
-                                  MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
-                                  MTHCA_TAVOR_CQ_DB_REQ_NOT)      |
-                                 to_mcq(cq)->cqn);
-       doorbell[1] = (__force __be32) 0xffffffff;
-
-       mthca_write64(doorbell,
-                     to_mdev(cq->device)->kar + MTHCA_CQ_DOORBELL,
+       mthca_write64(dbhi, 0xffffffff, to_mdev(cq->device)->kar + MTHCA_CQ_DOORBELL,
                      MTHCA_GET_DOORBELL_LOCK(&to_mdev(cq->device)->doorbell_lock));
 
        return 0;
@@ -750,19 +740,16 @@ int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags)
 int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
 {
        struct mthca_cq *cq = to_mcq(ibcq);
-       __be32 doorbell[2];
-       u32 sn;
-       __be32 ci;
-
-       sn = cq->arm_sn & 3;
-       ci = cpu_to_be32(cq->cons_index);
+       __be32 db_rec[2];
+       u32 dbhi;
+       u32 sn = cq->arm_sn & 3;
 
-       doorbell[0] = ci;
-       doorbell[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
-                                 ((flags & IB_CQ_SOLICITED_MASK) ==
-                                  IB_CQ_SOLICITED ? 1 : 2));
+       db_rec[0] = cpu_to_be32(cq->cons_index);
+       db_rec[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
+                               ((flags & IB_CQ_SOLICITED_MASK) ==
+                                IB_CQ_SOLICITED ? 1 : 2));
 
-       mthca_write_db_rec(doorbell, cq->arm_db);
+       mthca_write_db_rec(db_rec, cq->arm_db);
 
        /*
         * Make sure that the doorbell record in host memory is
@@ -770,14 +757,12 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
         */
        wmb();
 
-       doorbell[0] = cpu_to_be32((sn << 28)                       |
-                                 ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
-                                  MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
-                                  MTHCA_ARBEL_CQ_DB_REQ_NOT)      |
-                                 cq->cqn);
-       doorbell[1] = ci;
+       dbhi = (sn << 28) |
+               ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
+                MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
+                MTHCA_ARBEL_CQ_DB_REQ_NOT) | cq->cqn;
 
-       mthca_write64(doorbell,
+       mthca_write64(dbhi, cq->cons_index,
                      to_mdev(ibcq->device)->kar + MTHCA_CQ_DOORBELL,
                      MTHCA_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->doorbell_lock));
 
index dd9a44d..b374dc3 100644 (file)
@@ -58,10 +58,10 @@ static inline void mthca_write64_raw(__be64 val, void __iomem *dest)
        __raw_writeq((__force u64) val, dest);
 }
 
-static inline void mthca_write64(__be32 val[2], void __iomem *dest,
+static inline void mthca_write64(u32 hi, u32 lo, void __iomem *dest,
                                 spinlock_t *doorbell_lock)
 {
-       __raw_writeq(*(u64 *) val, dest);
+       __raw_writeq((__force u64) cpu_to_be64((u64) hi << 32 | lo), dest);
 }
 
 static inline void mthca_write_db_rec(__be32 val[2], __be32 *db)
@@ -87,14 +87,17 @@ static inline void mthca_write64_raw(__be64 val, void __iomem *dest)
        __raw_writel(((__force u32 *) &val)[1], dest + 4);
 }
 
-static inline void mthca_write64(__be32 val[2], void __iomem *dest,
+static inline void mthca_write64(u32 hi, u32 lo, void __iomem *dest,
                                 spinlock_t *doorbell_lock)
 {
        unsigned long flags;
 
+       hi = (__force u32) cpu_to_be32(hi);
+       lo = (__force u32) cpu_to_be32(lo);
+
        spin_lock_irqsave(doorbell_lock, flags);
-       __raw_writel((__force u32) val[0], dest);
-       __raw_writel((__force u32) val[1], dest + 4);
+       __raw_writel(hi, dest);
+       __raw_writel(lo, dest + 4);
        spin_unlock_irqrestore(doorbell_lock, flags);
 }
 
index 8592b26..b29de51 100644 (file)
@@ -173,11 +173,6 @@ static inline u64 async_mask(struct mthca_dev *dev)
 
 static inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
 {
-       __be32 doorbell[2];
-
-       doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_SET_CI | eq->eqn);
-       doorbell[1] = cpu_to_be32(ci & (eq->nent - 1));
-
        /*
         * This barrier makes sure that all updates to ownership bits
         * done by set_eqe_hw() hit memory before the consumer index
@@ -187,7 +182,7 @@ static inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u
         * having set_eqe_hw() overwrite the owner field.
         */
        wmb();
-       mthca_write64(doorbell,
+       mthca_write64(MTHCA_EQ_DB_SET_CI | eq->eqn, ci & (eq->nent - 1),
                      dev->kar + MTHCA_EQ_DOORBELL,
                      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
 }
@@ -212,12 +207,7 @@ static inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
 
 static inline void tavor_eq_req_not(struct mthca_dev *dev, int eqn)
 {
-       __be32 doorbell[2];
-
-       doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_REQ_NOT | eqn);
-       doorbell[1] = 0;
-
-       mthca_write64(doorbell,
+       mthca_write64(MTHCA_EQ_DB_REQ_NOT | eqn, 0,
                      dev->kar + MTHCA_EQ_DOORBELL,
                      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
 }
@@ -230,12 +220,7 @@ static inline void arbel_eq_req_not(struct mthca_dev *dev, u32 eqn_mask)
 static inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn)
 {
        if (!mthca_is_memfree(dev)) {
-               __be32 doorbell[2];
-
-               doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_DISARM_CQ | eqn);
-               doorbell[1] = cpu_to_be32(cqn);
-
-               mthca_write64(doorbell,
+               mthca_write64(MTHCA_EQ_DB_DISARM_CQ | eqn, cqn,
                              dev->kar + MTHCA_EQ_DOORBELL,
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
        }
index e61f3e6..007b381 100644 (file)
@@ -71,7 +71,7 @@ static void mthca_free_icm_pages(struct mthca_dev *dev, struct mthca_icm_chunk *
                             PCI_DMA_BIDIRECTIONAL);
 
        for (i = 0; i < chunk->npages; ++i)
-               __free_pages(chunk->mem[i].page,
+               __free_pages(sg_page(&chunk->mem[i]),
                             get_order(chunk->mem[i].length));
 }
 
@@ -81,7 +81,7 @@ static void mthca_free_icm_coherent(struct mthca_dev *dev, struct mthca_icm_chun
 
        for (i = 0; i < chunk->npages; ++i) {
                dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
-                                 lowmem_page_address(chunk->mem[i].page),
+                                 lowmem_page_address(sg_page(&chunk->mem[i])),
                                  sg_dma_address(&chunk->mem[i]));
        }
 }
@@ -107,10 +107,13 @@ void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent)
 
 static int mthca_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
 {
-       mem->page = alloc_pages(gfp_mask, order);
-       if (!mem->page)
+       struct page *page;
+
+       page = alloc_pages(gfp_mask, order);
+       if (!page)
                return -ENOMEM;
 
+       sg_set_page(mem, page);
        mem->length = PAGE_SIZE << order;
        mem->offset = 0;
        return 0;
@@ -157,6 +160,7 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
                        if (!chunk)
                                goto fail;
 
+                       sg_init_table(chunk->mem, MTHCA_ICM_CHUNK_LEN);
                        chunk->npages = 0;
                        chunk->nsg    = 0;
                        list_add_tail(&chunk->list, &icm->chunk_list);
@@ -304,7 +308,7 @@ void *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_h
                         * so if we found the page, dma_handle has already
                         * been assigned to. */
                        if (chunk->mem[i].length > offset) {
-                               page = chunk->mem[i].page;
+                               page = sg_page(&chunk->mem[i]);
                                goto out;
                        }
                        offset -= chunk->mem[i].length;
@@ -445,6 +449,7 @@ static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int pag
 int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
                      struct mthca_user_db_table *db_tab, int index, u64 uaddr)
 {
+       struct page *pages[1];
        int ret = 0;
        u8 status;
        int i;
@@ -472,16 +477,17 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
        }
 
        ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1, 1, 0,
-                            &db_tab->page[i].mem.page, NULL);
+                            pages, NULL);
        if (ret < 0)
                goto out;
 
+       sg_set_page(&db_tab->page[i].mem, pages[0]);
        db_tab->page[i].mem.length = MTHCA_ICM_PAGE_SIZE;
        db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK;
 
        ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
        if (ret < 0) {
-               put_page(db_tab->page[i].mem.page);
+               put_page(pages[0]);
                goto out;
        }
 
@@ -491,7 +497,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
                ret = -EINVAL;
        if (ret) {
                pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
-               put_page(db_tab->page[i].mem.page);
+               put_page(sg_page(&db_tab->page[i].mem));
                goto out;
        }
 
@@ -557,7 +563,7 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
                if (db_tab->page[i].uvirt) {
                        mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status);
                        pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
-                       put_page(db_tab->page[i].mem.page);
+                       put_page(sg_page(&db_tab->page[i].mem));
                }
        }
 
index df01b20..0e5461c 100644 (file)
@@ -1799,15 +1799,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
 out:
        if (likely(nreq)) {
-               __be32 doorbell[2];
-
-               doorbell[0] = cpu_to_be32(((qp->sq.next_ind << qp->sq.wqe_shift) +
-                                          qp->send_wqe_offset) | f0 | op0);
-               doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
-
                wmb();
 
-               mthca_write64(doorbell,
+               mthca_write64(((qp->sq.next_ind << qp->sq.wqe_shift) +
+                              qp->send_wqe_offset) | f0 | op0,
+                             (qp->qpn << 8) | size0,
                              dev->kar + MTHCA_SEND_DOORBELL,
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
                /*
@@ -1829,7 +1825,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 {
        struct mthca_dev *dev = to_mdev(ibqp->device);
        struct mthca_qp *qp = to_mqp(ibqp);
-       __be32 doorbell[2];
        unsigned long flags;
        int err = 0;
        int nreq;
@@ -1907,13 +1902,10 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
                        nreq = 0;
 
-                       doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
-                       doorbell[1] = cpu_to_be32(qp->qpn << 8);
-
                        wmb();
 
-                       mthca_write64(doorbell,
-                                     dev->kar + MTHCA_RECEIVE_DOORBELL,
+                       mthca_write64((qp->rq.next_ind << qp->rq.wqe_shift) | size0,
+                                     qp->qpn << 8, dev->kar + MTHCA_RECEIVE_DOORBELL,
                                      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
 
                        qp->rq.next_ind = ind;
@@ -1923,13 +1915,10 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 
 out:
        if (likely(nreq)) {
-               doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
-               doorbell[1] = cpu_to_be32((qp->qpn << 8) | nreq);
-
                wmb();
 
-               mthca_write64(doorbell,
-                             dev->kar + MTHCA_RECEIVE_DOORBELL,
+               mthca_write64((qp->rq.next_ind << qp->rq.wqe_shift) | size0,
+                             qp->qpn << 8 | nreq, dev->kar + MTHCA_RECEIVE_DOORBELL,
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
        }
 
@@ -1951,7 +1940,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 {
        struct mthca_dev *dev = to_mdev(ibqp->device);
        struct mthca_qp *qp = to_mqp(ibqp);
-       __be32 doorbell[2];
+       u32 dbhi;
        void *wqe;
        void *prev_wqe;
        unsigned long flags;
@@ -1981,10 +1970,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                if (unlikely(nreq == MTHCA_ARBEL_MAX_WQES_PER_SEND_DB)) {
                        nreq = 0;
 
-                       doorbell[0] = cpu_to_be32((MTHCA_ARBEL_MAX_WQES_PER_SEND_DB << 24) |
-                                                 ((qp->sq.head & 0xffff) << 8) |
-                                                 f0 | op0);
-                       doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
+                       dbhi = (MTHCA_ARBEL_MAX_WQES_PER_SEND_DB << 24) |
+                               ((qp->sq.head & 0xffff) << 8) | f0 | op0;
 
                        qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB;
 
@@ -2000,7 +1987,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                         * write MMIO send doorbell.
                         */
                        wmb();
-                       mthca_write64(doorbell,
+
+                       mthca_write64(dbhi, (qp->qpn << 8) | size0,
                                      dev->kar + MTHCA_SEND_DOORBELL,
                                      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
                }
@@ -2154,10 +2142,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
 out:
        if (likely(nreq)) {
-               doorbell[0] = cpu_to_be32((nreq << 24)                  |
-                                         ((qp->sq.head & 0xffff) << 8) |
-                                         f0 | op0);
-               doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
+               dbhi = (nreq << 24) | ((qp->sq.head & 0xffff) << 8) | f0 | op0;
 
                qp->sq.head += nreq;
 
@@ -2173,8 +2158,8 @@ out:
                 * write MMIO send doorbell.
                 */
                wmb();
-               mthca_write64(doorbell,
-                             dev->kar + MTHCA_SEND_DOORBELL,
+
+               mthca_write64(dbhi, (qp->qpn << 8) | size0, dev->kar + MTHCA_SEND_DOORBELL,
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
        }
 
index 3f58c11..553d681 100644 (file)
@@ -491,7 +491,6 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
 {
        struct mthca_dev *dev = to_mdev(ibsrq->device);
        struct mthca_srq *srq = to_msrq(ibsrq);
-       __be32 doorbell[2];
        unsigned long flags;
        int err = 0;
        int first_ind;
@@ -563,16 +562,13 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
                if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
                        nreq = 0;
 
-                       doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
-                       doorbell[1] = cpu_to_be32(srq->srqn << 8);
-
                        /*
                         * Make sure that descriptors are written
                         * before doorbell is rung.
                         */
                        wmb();
 
-                       mthca_write64(doorbell,
+                       mthca_write64(first_ind << srq->wqe_shift, srq->srqn << 8,
                                      dev->kar + MTHCA_RECEIVE_DOORBELL,
                                      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
 
@@ -581,16 +577,13 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
        }
 
        if (likely(nreq)) {
-               doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
-               doorbell[1] = cpu_to_be32((srq->srqn << 8) | nreq);
-
                /*
                 * Make sure that descriptors are written before
                 * doorbell is rung.
                 */
                wmb();
 
-               mthca_write64(doorbell,
+               mthca_write64(first_ind << srq->wqe_shift, (srq->srqn << 8) | nreq,
                              dev->kar + MTHCA_RECEIVE_DOORBELL,
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
        }
index 1b3327a..eb7edab 100644 (file)
@@ -84,9 +84,8 @@ enum {
        IPOIB_MCAST_RUN           = 6,
        IPOIB_STOP_REAPER         = 7,
        IPOIB_MCAST_STARTED       = 8,
-       IPOIB_FLAG_NETIF_STOPPED  = 9,
-       IPOIB_FLAG_ADMIN_CM       = 10,
-       IPOIB_FLAG_UMCAST         = 11,
+       IPOIB_FLAG_ADMIN_CM       = 9,
+       IPOIB_FLAG_UMCAST         = 10,
 
        IPOIB_MAX_BACKOFF_SECONDS = 16,
 
@@ -98,9 +97,9 @@ enum {
 
 #define        IPOIB_OP_RECV   (1ul << 31)
 #ifdef CONFIG_INFINIBAND_IPOIB_CM
-#define        IPOIB_CM_OP_SRQ (1ul << 30)
+#define        IPOIB_OP_CM     (1ul << 30)
 #else
-#define        IPOIB_CM_OP_SRQ (0)
+#define        IPOIB_OP_CM     (0)
 #endif
 
 /* structs */
@@ -197,7 +196,6 @@ struct ipoib_cm_rx {
 
 struct ipoib_cm_tx {
        struct ib_cm_id     *id;
-       struct ib_cq        *cq;
        struct ib_qp        *qp;
        struct list_head     list;
        struct net_device   *dev;
@@ -294,6 +292,7 @@ struct ipoib_dev_priv {
        unsigned             tx_tail;
        struct ib_sge        tx_sge;
        struct ib_send_wr    tx_wr;
+       unsigned             tx_outstanding;
 
        struct ib_wc ibwc[IPOIB_NUM_WC];
 
@@ -504,6 +503,7 @@ void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx);
 void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
                           unsigned int mtu);
 void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc);
+void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
 #else
 
 struct ipoib_cm_tx;
@@ -592,6 +592,9 @@ static inline void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *w
 {
 }
 
+static inline void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
+{
+}
 #endif
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
index 0a0dcb8..8761077 100644 (file)
@@ -87,7 +87,7 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
        struct ib_recv_wr *bad_wr;
        int i, ret;
 
-       priv->cm.rx_wr.wr_id = id | IPOIB_CM_OP_SRQ;
+       priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
 
        for (i = 0; i < IPOIB_CM_RX_SG; ++i)
                priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i];
@@ -401,7 +401,7 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
 void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
-       unsigned int wr_id = wc->wr_id & ~IPOIB_CM_OP_SRQ;
+       unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV);
        struct sk_buff *skb, *newskb;
        struct ipoib_cm_rx *p;
        unsigned long flags;
@@ -412,7 +412,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
                       wr_id, wc->status);
 
        if (unlikely(wr_id >= ipoib_recvq_size)) {
-               if (wr_id == (IPOIB_CM_RX_DRAIN_WRID & ~IPOIB_CM_OP_SRQ)) {
+               if (wr_id == (IPOIB_CM_RX_DRAIN_WRID & ~(IPOIB_OP_CM | IPOIB_OP_RECV))) {
                        spin_lock_irqsave(&priv->lock, flags);
                        list_splice_init(&priv->cm.rx_drain_list, &priv->cm.rx_reap_list);
                        ipoib_cm_start_rx_drain(priv);
@@ -434,7 +434,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
                goto repost;
        }
 
-       if (!likely(wr_id & IPOIB_CM_RX_UPDATE_MASK)) {
+       if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) {
                p = wc->qp->qp_context;
                if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
                        spin_lock_irqsave(&priv->lock, flags);
@@ -498,7 +498,7 @@ static inline int post_send(struct ipoib_dev_priv *priv,
        priv->tx_sge.addr             = addr;
        priv->tx_sge.length           = len;
 
-       priv->tx_wr.wr_id             = wr_id;
+       priv->tx_wr.wr_id             = wr_id | IPOIB_OP_CM;
 
        return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
 }
@@ -549,20 +549,19 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
                dev->trans_start = jiffies;
                ++tx->tx_head;
 
-               if (tx->tx_head - tx->tx_tail == ipoib_sendq_size) {
+               if (++priv->tx_outstanding == ipoib_sendq_size) {
                        ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n",
                                  tx->qp->qp_num);
                        netif_stop_queue(dev);
-                       set_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags);
                }
        }
 }
 
-static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx,
-                                 struct ib_wc *wc)
+void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
-       unsigned int wr_id = wc->wr_id;
+       struct ipoib_cm_tx *tx = wc->qp->qp_context;
+       unsigned int wr_id = wc->wr_id & ~IPOIB_OP_CM;
        struct ipoib_tx_buf *tx_req;
        unsigned long flags;
 
@@ -587,11 +586,10 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx
 
        spin_lock_irqsave(&priv->tx_lock, flags);
        ++tx->tx_tail;
-       if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags)) &&
-           tx->tx_head - tx->tx_tail <= ipoib_sendq_size >> 1) {
-               clear_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags);
+       if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
+           netif_queue_stopped(dev) &&
+           test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
                netif_wake_queue(dev);
-       }
 
        if (wc->status != IB_WC_SUCCESS &&
            wc->status != IB_WC_WR_FLUSH_ERR) {
@@ -614,11 +612,6 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx
                        tx->neigh = NULL;
                }
 
-               /* queue would be re-started anyway when TX is destroyed,
-                * but it makes sense to do it ASAP here. */
-               if (test_and_clear_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags))
-                       netif_wake_queue(dev);
-
                if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
                        list_move(&tx->list, &priv->cm.reap_list);
                        queue_work(ipoib_workqueue, &priv->cm.reap_task);
@@ -632,19 +625,6 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx
        spin_unlock_irqrestore(&priv->tx_lock, flags);
 }
 
-static void ipoib_cm_tx_completion(struct ib_cq *cq, void *tx_ptr)
-{
-       struct ipoib_cm_tx *tx = tx_ptr;
-       int n, i;
-
-       ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
-       do {
-               n = ib_poll_cq(cq, IPOIB_NUM_WC, tx->ibwc);
-               for (i = 0; i < n; ++i)
-                       ipoib_cm_handle_tx_wc(tx->dev, tx, tx->ibwc + i);
-       } while (n == IPOIB_NUM_WC);
-}
-
 int ipoib_cm_dev_open(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -807,17 +787,18 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even
        return 0;
 }
 
-static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ib_cq *cq)
+static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_cm_tx *tx)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ib_qp_init_attr attr = {
-               .send_cq                = cq,
+               .send_cq                = priv->cq,
                .recv_cq                = priv->cq,
                .srq                    = priv->cm.srq,
                .cap.max_send_wr        = ipoib_sendq_size,
                .cap.max_send_sge       = 1,
                .sq_sig_type            = IB_SIGNAL_ALL_WR,
                .qp_type                = IB_QPT_RC,
+               .qp_context             = tx
         };
 
        return ib_create_qp(priv->pd, &attr);
@@ -899,21 +880,7 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
                goto err_tx;
        }
 
-       p->cq = ib_create_cq(priv->ca, ipoib_cm_tx_completion, NULL, p,
-                            ipoib_sendq_size + 1, 0);
-       if (IS_ERR(p->cq)) {
-               ret = PTR_ERR(p->cq);
-               ipoib_warn(priv, "failed to allocate tx cq: %d\n", ret);
-               goto err_cq;
-       }
-
-       ret = ib_req_notify_cq(p->cq, IB_CQ_NEXT_COMP);
-       if (ret) {
-               ipoib_warn(priv, "failed to request completion notification: %d\n", ret);
-               goto err_req_notify;
-       }
-
-       p->qp = ipoib_cm_create_tx_qp(p->dev, p->cq);
+       p->qp = ipoib_cm_create_tx_qp(p->dev, p);
        if (IS_ERR(p->qp)) {
                ret = PTR_ERR(p->qp);
                ipoib_warn(priv, "failed to allocate tx qp: %d\n", ret);
@@ -950,12 +917,8 @@ err_modify:
 err_id:
        p->id = NULL;
        ib_destroy_qp(p->qp);
-err_req_notify:
 err_qp:
        p->qp = NULL;
-       ib_destroy_cq(p->cq);
-err_cq:
-       p->cq = NULL;
 err_tx:
        return ret;
 }
@@ -964,6 +927,8 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
 {
        struct ipoib_dev_priv *priv = netdev_priv(p->dev);
        struct ipoib_tx_buf *tx_req;
+       unsigned long flags;
+       unsigned long begin;
 
        ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n",
                  p->qp ? p->qp->qp_num : 0, p->tx_head, p->tx_tail);
@@ -971,27 +936,40 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
        if (p->id)
                ib_destroy_cm_id(p->id);
 
-       if (p->qp)
-               ib_destroy_qp(p->qp);
-
-       if (p->cq)
-               ib_destroy_cq(p->cq);
-
-       if (test_bit(IPOIB_FLAG_NETIF_STOPPED, &p->flags))
-               netif_wake_queue(p->dev);
-
        if (p->tx_ring) {
+               /* Wait for all sends to complete */
+               begin = jiffies;
                while ((int) p->tx_tail - (int) p->tx_head < 0) {
-                       tx_req = &p->tx_ring[p->tx_tail & (ipoib_sendq_size - 1)];
-                       ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len,
-                                        DMA_TO_DEVICE);
-                       dev_kfree_skb_any(tx_req->skb);
-                       ++p->tx_tail;
+                       if (time_after(jiffies, begin + 5 * HZ)) {
+                               ipoib_warn(priv, "timing out; %d sends not completed\n",
+                                          p->tx_head - p->tx_tail);
+                               goto timeout;
+                       }
+
+                       msleep(1);
                }
+       }
 
-               kfree(p->tx_ring);
+timeout:
+
+       while ((int) p->tx_tail - (int) p->tx_head < 0) {
+               tx_req = &p->tx_ring[p->tx_tail & (ipoib_sendq_size - 1)];
+               ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len,
+                                   DMA_TO_DEVICE);
+               dev_kfree_skb_any(tx_req->skb);
+               ++p->tx_tail;
+               spin_lock_irqsave(&priv->tx_lock, flags);
+               if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
+                   netif_queue_stopped(p->dev) &&
+                   test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
+                       netif_wake_queue(p->dev);
+               spin_unlock_irqrestore(&priv->tx_lock, flags);
        }
 
+       if (p->qp)
+               ib_destroy_qp(p->qp);
+
+       kfree(p->tx_ring);
        kfree(p);
 }
 
index 1a77e79..5063dd5 100644 (file)
@@ -267,11 +267,10 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
 
        spin_lock_irqsave(&priv->tx_lock, flags);
        ++priv->tx_tail;
-       if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags)) &&
-           priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1) {
-               clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
+       if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
+           netif_queue_stopped(dev) &&
+           test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
                netif_wake_queue(dev);
-       }
        spin_unlock_irqrestore(&priv->tx_lock, flags);
 
        if (wc->status != IB_WC_SUCCESS &&
@@ -301,14 +300,18 @@ poll_more:
                for (i = 0; i < n; i++) {
                        struct ib_wc *wc = priv->ibwc + i;
 
-                       if (wc->wr_id & IPOIB_CM_OP_SRQ) {
-                               ++done;
-                               ipoib_cm_handle_rx_wc(dev, wc);
-                       } else if (wc->wr_id & IPOIB_OP_RECV) {
+                       if (wc->wr_id & IPOIB_OP_RECV) {
                                ++done;
-                               ipoib_ib_handle_rx_wc(dev, wc);
-                       } else
-                               ipoib_ib_handle_tx_wc(dev, wc);
+                               if (wc->wr_id & IPOIB_OP_CM)
+                                       ipoib_cm_handle_rx_wc(dev, wc);
+                               else
+                                       ipoib_ib_handle_rx_wc(dev, wc);
+                       } else {
+                               if (wc->wr_id & IPOIB_OP_CM)
+                                       ipoib_cm_handle_tx_wc(dev, wc);
+                               else
+                                       ipoib_ib_handle_tx_wc(dev, wc);
+                       }
                }
 
                if (n != t)
@@ -401,10 +404,9 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
                address->last_send = priv->tx_head;
                ++priv->tx_head;
 
-               if (priv->tx_head - priv->tx_tail == ipoib_sendq_size) {
+               if (++priv->tx_outstanding == ipoib_sendq_size) {
                        ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
                        netif_stop_queue(dev);
-                       set_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
                }
        }
 }
@@ -436,7 +438,8 @@ void ipoib_reap_ah(struct work_struct *work)
        __ipoib_reap_ah(dev);
 
        if (!test_bit(IPOIB_STOP_REAPER, &priv->flags))
-               queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, HZ);
+               queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
+                                  round_jiffies_relative(HZ));
 }
 
 int ipoib_ib_dev_open(struct net_device *dev)
@@ -472,7 +475,8 @@ int ipoib_ib_dev_open(struct net_device *dev)
        }
 
        clear_bit(IPOIB_STOP_REAPER, &priv->flags);
-       queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, HZ);
+       queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
+                          round_jiffies_relative(HZ));
 
        set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
 
@@ -561,12 +565,17 @@ void ipoib_drain_cq(struct net_device *dev)
                        if (priv->ibwc[i].status == IB_WC_SUCCESS)
                                priv->ibwc[i].status = IB_WC_WR_FLUSH_ERR;
 
-                       if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ)
-                               ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
-                       else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV)
-                               ipoib_ib_handle_rx_wc(dev, priv->ibwc + i);
-                       else
-                               ipoib_ib_handle_tx_wc(dev, priv->ibwc + i);
+                       if (priv->ibwc[i].wr_id & IPOIB_OP_RECV) {
+                               if (priv->ibwc[i].wr_id & IPOIB_OP_CM)
+                                       ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
+                               else
+                                       ipoib_ib_handle_rx_wc(dev, priv->ibwc + i);
+                       } else {
+                               if (priv->ibwc[i].wr_id & IPOIB_OP_CM)
+                                       ipoib_cm_handle_tx_wc(dev, priv->ibwc + i);
+                               else
+                                       ipoib_ib_handle_tx_wc(dev, priv->ibwc + i);
+                       }
                }
        } while (n == IPOIB_NUM_WC);
 }
@@ -612,6 +621,7 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush)
                                                    DMA_TO_DEVICE);
                                dev_kfree_skb_any(tx_req->skb);
                                ++priv->tx_tail;
+                               --priv->tx_outstanding;
                        }
 
                        for (i = 0; i < ipoib_recvq_size; ++i) {
index 362610d..a03a65e 100644 (file)
@@ -148,8 +148,6 @@ static int ipoib_stop(struct net_device *dev)
 
        netif_stop_queue(dev);
 
-       clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
-
        /*
         * Now flush workqueue to make sure a scheduled task doesn't
         * bring our internal state back up.
@@ -902,7 +900,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
                goto out_rx_ring_cleanup;
        }
 
-       /* priv->tx_head & tx_tail are already 0 */
+       /* priv->tx_head, tx_tail & tx_outstanding are already 0 */
 
        if (ipoib_ib_dev_init(dev, ca, port))
                goto out_tx_ring_cleanup;
index f3529b6..d687980 100644 (file)
@@ -131,7 +131,7 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
 
                p = mem;
                for_each_sg(sgl, sg, data->size, i) {
-                       from = kmap_atomic(sg->page, KM_USER0);
+                       from = kmap_atomic(sg_page(sg), KM_USER0);
                        memcpy(p,
                               from + sg->offset,
                               sg->length);
@@ -191,7 +191,7 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
 
                p = mem;
                for_each_sg(sgl, sg, sg_size, i) {
-                       to = kmap_atomic(sg->page, KM_SOFTIRQ0);
+                       to = kmap_atomic(sg_page(sg), KM_SOFTIRQ0);
                        memcpy(to + sg->offset,
                               p,
                               sg->length);
@@ -300,7 +300,7 @@ static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data,
        for_each_sg(sgl, sg, data->dma_nents, i) {
                /* iser_dbg("Checking sg iobuf [%d]: phys=0x%08lX "
                   "offset: %ld sz: %ld\n", i,
-                  (unsigned long)page_to_phys(sg->page),
+                  (unsigned long)sg_phys(sg),
                   (unsigned long)sg->offset,
                   (unsigned long)sg->length); */
                end_addr = ib_sg_dma_address(ibdev, sg) +
@@ -336,7 +336,7 @@ static void iser_data_buf_dump(struct iser_data_buf *data,
                iser_err("sg[%d] dma_addr:0x%lX page:0x%p "
                         "off:0x%x sz:0x%x dma_len:0x%x\n",
                         i, (unsigned long)ib_sg_dma_address(ibdev, sg),
-                        sg->page, sg->offset,
+                        sg_page(sg), sg->offset,
                         sg->length, ib_sg_dma_len(ibdev, sg));
 }
 
index a67b29b..e5f4da9 100644 (file)
@@ -256,7 +256,6 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
                printk(KERN_ERR DRV_NAME
                        ": unable to claim irq %d; error %d\n",
                        bf54x_kpad->irq, error);
-               error = -EBUSY;
                goto out2;
        }
 
index 0117817..f132702 100644 (file)
@@ -504,25 +504,22 @@ static void atp_complete(struct urb* urb)
                memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
        }
 
-       /* Geyser 3 will continue to send packets continually after
+       input_report_key(dev->input, BTN_LEFT, key);
+       input_sync(dev->input);
+
+       /* Many Geysers will continue to send packets continually after
           the first touch unless reinitialised. Do so if it's been
           idle for a while in order to avoid waking the kernel up
           several hundred times a second */
 
-       if (atp_is_geyser_3(dev)) {
-               if (!x && !y && !key) {
-                       dev->idlecount++;
-                       if (dev->idlecount == 10) {
-                               dev->valid = 0;
-                               schedule_work(&dev->work);
-                       }
+       if (!x && !y && !key) {
+               dev->idlecount++;
+               if (dev->idlecount == 10) {
+                       dev->valid = 0;
+                       schedule_work(&dev->work);
                }
-               else
-                       dev->idlecount = 0;
-       }
-
-       input_report_key(dev->input, BTN_LEFT, key);
-       input_sync(dev->input);
+       } else
+               dev->idlecount = 0;
 
 exit:
        retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
index 11dafc0..1a0cea3 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/err.h>
 #include <linux/rcupdate.h>
 #include <linux/platform_device.h>
+#include <linux/i8042.h>
 
 #include <asm/io.h>
 
@@ -208,7 +209,7 @@ static int __i8042_command(unsigned char *param, int command)
        return 0;
 }
 
-static int i8042_command(unsigned char *param, int command)
+int i8042_command(unsigned char *param, int command)
 {
        unsigned long flags;
        int retval;
@@ -219,6 +220,7 @@ static int i8042_command(unsigned char *param, int command)
 
        return retval;
 }
+EXPORT_SYMBOL(i8042_command);
 
 /*
  * i8042_kbd_write() sends a byte out through the keyboard interface.
index b3eb7a7..dd22d91 100644 (file)
 #define I8042_CTR_AUXDIS       0x20
 #define I8042_CTR_XLATE                0x40
 
-/*
- * Commands.
- */
-
-#define I8042_CMD_CTL_RCTR     0x0120
-#define I8042_CMD_CTL_WCTR     0x1060
-#define I8042_CMD_CTL_TEST     0x01aa
-
-#define I8042_CMD_KBD_DISABLE  0x00ad
-#define I8042_CMD_KBD_ENABLE   0x00ae
-#define I8042_CMD_KBD_TEST     0x01ab
-#define I8042_CMD_KBD_LOOP     0x11d2
-
-#define I8042_CMD_AUX_DISABLE  0x00a7
-#define I8042_CMD_AUX_ENABLE   0x00a8
-#define I8042_CMD_AUX_TEST     0x01a9
-#define I8042_CMD_AUX_SEND     0x10d4
-#define I8042_CMD_AUX_LOOP     0x11d3
-
-#define I8042_CMD_MUX_PFX      0x0090
-#define I8042_CMD_MUX_SEND     0x1090
-
 /*
  * Return codes.
  */
index e3e0baa..fa8442b 100644 (file)
@@ -202,6 +202,7 @@ config TOUCHSCREEN_USB_COMPOSITE
          - DMC TSC-10/25
          - IRTOUCHSYSTEMS/UNITOP
          - IdealTEK URTC1000
+         - GoTop Super_Q2/GogoPen/PenPower tablets
 
          Have a look at <http://linux.chapter7.ch/touchkit/> for
          a usage description and the required user-space stuff.
@@ -259,4 +260,9 @@ config TOUCHSCREEN_USB_GENERAL_TOUCH
        bool "GeneralTouch Touchscreen device support" if EMBEDDED
        depends on TOUCHSCREEN_USB_COMPOSITE
 
+config TOUCHSCREEN_USB_GOTOP
+       default y
+       bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
+       depends on TOUCHSCREEN_USB_COMPOSITE
+
 endif
index 5f34b78..19055e7 100644 (file)
@@ -11,8 +11,9 @@
  *  - DMC TSC-10/25
  *  - IRTOUCHSYSTEMS/UNITOP
  *  - IdealTEK URTC1000
+ *  - GoTop Super_Q2/GogoPen/PenPower tablets
  *
- * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
+ * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
  *
  * This program is free software; you can redistribute it and/or
@@ -115,6 +116,7 @@ enum {
        DEVTYPE_IRTOUCH,
        DEVTYPE_IDEALTEK,
        DEVTYPE_GENERAL_TOUCH,
+       DEVTYPE_GOTOP,
 };
 
 static struct usb_device_id usbtouch_devices[] = {
@@ -168,6 +170,12 @@ static struct usb_device_id usbtouch_devices[] = {
        {USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH},
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+       {USB_DEVICE(0x08f2, 0x007f), .driver_info = DEVTYPE_GOTOP},
+       {USB_DEVICE(0x08f2, 0x00ce), .driver_info = DEVTYPE_GOTOP},
+       {USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
+#endif
+
        {}
 };
 
@@ -500,6 +508,20 @@ static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 }
 #endif
 
+/*****************************************************************************
+ * GoTop Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+       dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
+       dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
+       dev->touch = pkt[0] & 0x01;
+       return 1;
+}
+#endif
+
+
 /*****************************************************************************
  * the different device descriptors
  */
@@ -623,9 +645,19 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
                .max_yc         = 0x0500,
                .rept_size      = 7,
                .read_data      = general_touch_read_data,
-       }
+       },
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+       [DEVTYPE_GOTOP] = {
+               .min_xc         = 0x0,
+               .max_xc         = 0x03ff,
+               .min_yc         = 0x0,
+               .max_yc         = 0x03ff,
+               .rept_size      = 4,
+               .read_data      = gotop_read_data,
+       },
+#endif
 };
 
 
index 8749fa4..6569206 100644 (file)
@@ -47,4 +47,8 @@ config KVM_AMD
          Provides support for KVM on AMD processors equipped with the AMD-V
          (SVM) extensions.
 
+# OK, it's a little counter-intuitive to do this, but it puts it neatly under
+# the virtualization menu.
+source drivers/lguest/Kconfig
+
 endif # VIRTUALIZATION
index af2d288..07ae280 100644 (file)
@@ -198,21 +198,15 @@ static void vcpu_put(struct kvm_vcpu *vcpu)
 
 static void ack_flush(void *_completed)
 {
-       atomic_t *completed = _completed;
-
-       atomic_inc(completed);
 }
 
 void kvm_flush_remote_tlbs(struct kvm *kvm)
 {
-       int i, cpu, needed;
+       int i, cpu;
        cpumask_t cpus;
        struct kvm_vcpu *vcpu;
-       atomic_t completed;
 
-       atomic_set(&completed, 0);
        cpus_clear(cpus);
-       needed = 0;
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                vcpu = kvm->vcpus[i];
                if (!vcpu)
@@ -221,23 +215,9 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
                        continue;
                cpu = vcpu->cpu;
                if (cpu != -1 && cpu != raw_smp_processor_id())
-                       if (!cpu_isset(cpu, cpus)) {
-                               cpu_set(cpu, cpus);
-                               ++needed;
-                       }
-       }
-
-       /*
-        * We really want smp_call_function_mask() here.  But that's not
-        * available, so ipi all cpus in parallel and wait for them
-        * to complete.
-        */
-       for (cpu = first_cpu(cpus); cpu != NR_CPUS; cpu = next_cpu(cpu, cpus))
-               smp_call_function_single(cpu, ack_flush, &completed, 1, 0);
-       while (atomic_read(&completed) != needed) {
-               cpu_relax();
-               barrier();
+                       cpu_set(cpu, cpus);
        }
+       smp_call_function_mask(cpus, ack_flush, NULL, 1);
 }
 
 int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
@@ -2054,12 +2034,21 @@ again:
 
        kvm_x86_ops->run(vcpu, kvm_run);
 
-       kvm_guest_exit();
        vcpu->guest_mode = 0;
        local_irq_enable();
 
        ++vcpu->stat.exits;
 
+       /*
+        * We must have an instruction between local_irq_enable() and
+        * kvm_guest_exit(), so the timer interrupt isn't delayed by
+        * the interrupt shadow.  The stat.exits increment will do nicely.
+        * But we need to prevent reordering, hence this barrier():
+        */
+       barrier();
+
+       kvm_guest_exit();
+
        preempt_enable();
 
        /*
index a190587..238fcad 100644 (file)
@@ -494,12 +494,19 @@ static void apic_send_ipi(struct kvm_lapic *apic)
 
 static u32 apic_get_tmcct(struct kvm_lapic *apic)
 {
-       u32 counter_passed;
-       ktime_t passed, now = apic->timer.dev.base->get_time();
-       u32 tmcct = apic_get_reg(apic, APIC_TMICT);
+       u64 counter_passed;
+       ktime_t passed, now;
+       u32 tmcct;
 
        ASSERT(apic != NULL);
 
+       now = apic->timer.dev.base->get_time();
+       tmcct = apic_get_reg(apic, APIC_TMICT);
+
+       /* if initial count is 0, current count should also be 0 */
+       if (tmcct == 0)
+               return 0;
+
        if (unlikely(ktime_to_ns(now) <=
                ktime_to_ns(apic->timer.last_update))) {
                /* Wrap around */
@@ -514,15 +521,24 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
 
        counter_passed = div64_64(ktime_to_ns(passed),
                                  (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
-       tmcct -= counter_passed;
 
-       if (tmcct <= 0) {
-               if (unlikely(!apic_lvtt_period(apic)))
+       if (counter_passed > tmcct) {
+               if (unlikely(!apic_lvtt_period(apic))) {
+                       /* one-shot timers stick at 0 until reset */
                        tmcct = 0;
-               else
-                       do {
-                               tmcct += apic_get_reg(apic, APIC_TMICT);
-                       } while (tmcct <= 0);
+               } else {
+                       /*
+                        * periodic timers reset to APIC_TMICT when they
+                        * hit 0. The while loop simulates this happening N
+                        * times. (counter_passed %= tmcct) would also work,
+                        * but might be slower or not work on 32-bit??
+                        */
+                       while (counter_passed > tmcct)
+                               counter_passed -= tmcct;
+                       tmcct -= counter_passed;
+               }
+       } else {
+               tmcct -= counter_passed;
        }
 
        return tmcct;
@@ -853,7 +869,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
                apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
                apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
        }
-       apic->timer.divide_count = 0;
+       update_divide_count(apic);
        atomic_set(&apic->timer.pending, 0);
        if (vcpu->vcpu_id == 0)
                vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
index 6d84d30..feb5ac9 100644 (file)
@@ -1049,6 +1049,7 @@ int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
        destroy_kvm_mmu(vcpu);
        return init_kvm_mmu(vcpu);
 }
+EXPORT_SYMBOL_GPL(kvm_mmu_reset_context);
 
 int kvm_mmu_load(struct kvm_vcpu *vcpu)
 {
@@ -1088,7 +1089,7 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
                        mmu_page_remove_parent_pte(child, spte);
                }
        }
-       *spte = 0;
+       set_shadow_pte(spte, 0);
        kvm_flush_remote_tlbs(vcpu->kvm);
 }
 
index 4f115a8..bb56ae3 100644 (file)
@@ -523,6 +523,8 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
 
 static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
+       if (vcpu->rmode.active)
+               rflags |= IOPL_MASK | X86_EFLAGS_VM;
        vmcs_writel(GUEST_RFLAGS, rflags);
 }
 
@@ -1128,6 +1130,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
        fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs);
        fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs);
 
+       kvm_mmu_reset_context(vcpu);
        init_rmode_tss(vcpu->kvm);
 }
 
@@ -1760,10 +1763,8 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
        }
 
-       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */
-               asm ("int $2");
-               return 1;
-       }
+       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */
+               return 1;  /* already handled by vmx_vcpu_run() */
 
        if (is_no_device(intr_info)) {
                vmx_fpu_activate(vcpu);
@@ -2196,6 +2197,7 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
 static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u32 intr_info;
 
        /*
         * Loading guest fpu may have cleared host cr0.ts
@@ -2322,6 +2324,12 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
        asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
        vmx->launched = 1;
+
+       intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+
+       /* We need to handle NMIs before interrupts are enabled */
+       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */
+               asm("int $2");
 }
 
 static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
index 9737c3b..a6ace30 100644 (file)
@@ -212,7 +212,8 @@ static u16 twobyte_table[256] = {
        0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
            DstReg | SrcMem16 | ModRM | Mov,
        /* 0xC0 - 0xCF */
-       0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, DstMem | SrcReg | ModRM | Mov, 0, 0, 0, ImplicitOps | ModRM,
+       0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xD0 - 0xDF */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xE0 - 0xEF */
@@ -596,11 +597,10 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
                case 0xf0:      /* LOCK */
                        lock_prefix = 1;
                        break;
+               case 0xf2:      /* REPNE/REPNZ */
                case 0xf3:      /* REP/REPE/REPZ */
                        rep_prefix = 1;
                        break;
-               case 0xf2:      /* REPNE/REPNZ */
-                       break;
                default:
                        goto done_prefixes;
                }
@@ -825,6 +825,14 @@ done_prefixes:
                if (twobyte && b == 0x01 && modrm_reg == 7)
                        break;
              srcmem_common:
+               /*
+                * For instructions with a ModR/M byte, switch to register
+                * access if Mod = 3.
+                */
+               if ((d & ModRM) && modrm_mod == 3) {
+                       src.type = OP_REG;
+                       break;
+               }
                src.type = OP_MEM;
                src.ptr = (unsigned long *)cr2;
                src.val = 0;
@@ -893,6 +901,14 @@ done_prefixes:
                dst.ptr = (unsigned long *)cr2;
                dst.bytes = (d & ByteOp) ? 1 : op_bytes;
                dst.val = 0;
+               /*
+                * For instructions with a ModR/M byte, switch to register
+                * access if Mod = 3.
+                */
+               if ((d & ModRM) && modrm_mod == 3) {
+                       dst.type = OP_REG;
+                       break;
+               }
                if (d & BitOp) {
                        unsigned long mask = ~(dst.bytes * 8 - 1);
 
@@ -1083,31 +1099,6 @@ push:
        case 0xd2 ... 0xd3:     /* Grp2 */
                src.val = _regs[VCPU_REGS_RCX];
                goto grp2;
-       case 0xe8: /* call (near) */ {
-               long int rel;
-               switch (op_bytes) {
-               case 2:
-                       rel = insn_fetch(s16, 2, _eip);
-                       break;
-               case 4:
-                       rel = insn_fetch(s32, 4, _eip);
-                       break;
-               case 8:
-                       rel = insn_fetch(s64, 8, _eip);
-                       break;
-               default:
-                       DPRINTF("Call: Invalid op_bytes\n");
-                       goto cannot_emulate;
-               }
-               src.val = (unsigned long) _eip;
-               JMP_REL(rel);
-               goto push;
-       }
-       case 0xe9: /* jmp rel */
-       case 0xeb: /* jmp rel short */
-               JMP_REL(src.val);
-               no_wb = 1; /* Disable writeback. */
-               break;
        case 0xf6 ... 0xf7:     /* Grp3 */
                switch (modrm_reg) {
                case 0 ... 1:   /* test */
@@ -1350,6 +1341,32 @@ special_insn:
        case 0xae ... 0xaf:     /* scas */
                DPRINTF("Urk! I don't handle SCAS.\n");
                goto cannot_emulate;
+       case 0xe8: /* call (near) */ {
+               long int rel;
+               switch (op_bytes) {
+               case 2:
+                       rel = insn_fetch(s16, 2, _eip);
+                       break;
+               case 4:
+                       rel = insn_fetch(s32, 4, _eip);
+                       break;
+               case 8:
+                       rel = insn_fetch(s64, 8, _eip);
+                       break;
+               default:
+                       DPRINTF("Call: Invalid op_bytes\n");
+                       goto cannot_emulate;
+               }
+               src.val = (unsigned long) _eip;
+               JMP_REL(rel);
+               goto push;
+       }
+       case 0xe9: /* jmp rel */
+       case 0xeb: /* jmp rel short */
+               JMP_REL(src.val);
+               no_wb = 1; /* Disable writeback. */
+               break;
+
 
        }
        goto writeback;
@@ -1501,6 +1518,10 @@ twobyte_insn:
                dst.bytes = op_bytes;
                dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val;
                break;
+       case 0xc3:              /* movnti */
+               dst.bytes = op_bytes;
+               dst.val = (op_bytes == 4) ? (u32) src.val : (u64) src.val;
+               break;
        }
        goto writeback;
 
index 41e2250..7eb9ecf 100644 (file)
@@ -1,7 +1,6 @@
 config LGUEST
        tristate "Linux hypervisor example code"
-       depends on X86 && PARAVIRT && EXPERIMENTAL && !X86_PAE && FUTEX
-       select LGUEST_GUEST
+       depends on X86_32 && EXPERIMENTAL && !X86_PAE && FUTEX && !(X86_VISWS || X86_VOYAGER)
        select HVC_DRIVER
        ---help---
          This is a very simple module which allows you to run
@@ -18,13 +17,3 @@ config LGUEST_GUEST
          The guest needs code built-in, even if the host has lguest
          support as a module.  The drivers are tiny, so we build them
          in too.
-
-config LGUEST_NET
-       tristate
-       default y
-       depends on LGUEST_GUEST && NET
-
-config LGUEST_BLOCK
-       tristate
-       default y
-       depends on LGUEST_GUEST && BLOCK
index e504747..5e8272d 100644 (file)
@@ -1,10 +1,12 @@
-# Guest requires the paravirt_ops replacement and the bus driver.
-obj-$(CONFIG_LGUEST_GUEST) += lguest.o lguest_asm.o lguest_bus.o
+# Guest requires the device configuration and probing code.
+obj-$(CONFIG_LGUEST_GUEST) += lguest_device.o
 
 # Host requires the other files, which can be a module.
 obj-$(CONFIG_LGUEST)   += lg.o
-lg-y := core.o hypercalls.o page_tables.o interrupts_and_traps.o \
-       segments.o io.o lguest_user.o switcher.o
+lg-y = core.o hypercalls.o page_tables.o interrupts_and_traps.o \
+       segments.o lguest_user.o
+
+lg-$(CONFIG_X86_32) += x86/switcher_32.o x86/core.o
 
 Preparation Preparation!: PREFIX=P
 Guest: PREFIX=G
index a0788c1..35d19ae 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/cpu.h>
 #include <linux/freezer.h>
+#include <linux/highmem.h>
 #include <asm/paravirt.h>
-#include <asm/desc.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/poll.h>
-#include <asm/highmem.h>
 #include <asm/asm-offsets.h>
-#include <asm/i387.h>
 #include "lg.h"
 
-/* Found in switcher.S */
-extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
-extern unsigned long default_idt_entries[];
-
-/* Every guest maps the core switcher code. */
-#define SHARED_SWITCHER_PAGES \
-       DIV_ROUND_UP(end_switcher_text - start_switcher_text, PAGE_SIZE)
-/* Pages for switcher itself, then two pages per cpu */
-#define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * NR_CPUS)
-
-/* We map at -4M for ease of mapping into the guest (one PTE page). */
-#define SWITCHER_ADDR 0xFFC00000
 
 static struct vm_struct *switcher_vma;
 static struct page **switcher_page;
 
-static int cpu_had_pge;
-static struct {
-       unsigned long offset;
-       unsigned short segment;
-} lguest_entry;
-
 /* This One Big lock protects all inter-guest data structures. */
 DEFINE_MUTEX(lguest_lock);
-static DEFINE_PER_CPU(struct lguest *, last_guest);
-
-/* FIXME: Make dynamic. */
-#define MAX_LGUEST_GUESTS 16
-struct lguest lguests[MAX_LGUEST_GUESTS];
-
-/* Offset from where switcher.S was compiled to where we've copied it */
-static unsigned long switcher_offset(void)
-{
-       return SWITCHER_ADDR - (unsigned long)start_switcher_text;
-}
-
-/* This cpu's struct lguest_pages. */
-static struct lguest_pages *lguest_pages(unsigned int cpu)
-{
-       return &(((struct lguest_pages *)
-                 (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
-}
 
 /*H:010 We need to set up the Switcher at a high virtual address.  Remember the
  * Switcher is a few hundred bytes of assembler code which actually changes the
@@ -73,9 +35,7 @@ static struct lguest_pages *lguest_pages(unsigned int cpu)
  * Host since it will be running as the switchover occurs.
  *
  * Trying to map memory at a particular address is an unusual thing to do, so
- * it's not a simple one-liner.  We also set up the per-cpu parts of the
- * Switcher here.
- */
+ * it's not a simple one-liner. */
 static __init int map_switcher(void)
 {
        int i, err;
@@ -132,90 +92,11 @@ static __init int map_switcher(void)
                goto free_vma;
        }
 
-       /* Now the switcher is mapped at the right address, we can't fail!
-        * Copy in the compiled-in Switcher code (from switcher.S). */
+       /* Now the Switcher is mapped at the right address, we can't fail!
+        * Copy in the compiled-in Switcher code (from <arch>_switcher.S). */
        memcpy(switcher_vma->addr, start_switcher_text,
               end_switcher_text - start_switcher_text);
 
-       /* Most of the switcher.S doesn't care that it's been moved; on Intel,
-        * jumps are relative, and it doesn't access any references to external
-        * code or data.
-        *
-        * The only exception is the interrupt handlers in switcher.S: their
-        * addresses are placed in a table (default_idt_entries), so we need to
-        * update the table with the new addresses.  switcher_offset() is a
-        * convenience function which returns the distance between the builtin
-        * switcher code and the high-mapped copy we just made. */
-       for (i = 0; i < IDT_ENTRIES; i++)
-               default_idt_entries[i] += switcher_offset();
-
-       /*
-        * Set up the Switcher's per-cpu areas.
-        *
-        * Each CPU gets two pages of its own within the high-mapped region
-        * (aka. "struct lguest_pages").  Much of this can be initialized now,
-        * but some depends on what Guest we are running (which is set up in
-        * copy_in_guest_info()).
-        */
-       for_each_possible_cpu(i) {
-               /* lguest_pages() returns this CPU's two pages. */
-               struct lguest_pages *pages = lguest_pages(i);
-               /* This is a convenience pointer to make the code fit one
-                * statement to a line. */
-               struct lguest_ro_state *state = &pages->state;
-
-               /* The Global Descriptor Table: the Host has a different one
-                * for each CPU.  We keep a descriptor for the GDT which says
-                * where it is and how big it is (the size is actually the last
-                * byte, not the size, hence the "-1"). */
-               state->host_gdt_desc.size = GDT_SIZE-1;
-               state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
-
-               /* All CPUs on the Host use the same Interrupt Descriptor
-                * Table, so we just use store_idt(), which gets this CPU's IDT
-                * descriptor. */
-               store_idt(&state->host_idt_desc);
-
-               /* The descriptors for the Guest's GDT and IDT can be filled
-                * out now, too.  We copy the GDT & IDT into ->guest_gdt and
-                * ->guest_idt before actually running the Guest. */
-               state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
-               state->guest_idt_desc.address = (long)&state->guest_idt;
-               state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
-               state->guest_gdt_desc.address = (long)&state->guest_gdt;
-
-               /* We know where we want the stack to be when the Guest enters
-                * the switcher: in pages->regs.  The stack grows upwards, so
-                * we start it at the end of that structure. */
-               state->guest_tss.esp0 = (long)(&pages->regs + 1);
-               /* And this is the GDT entry to use for the stack: we keep a
-                * couple of special LGUEST entries. */
-               state->guest_tss.ss0 = LGUEST_DS;
-
-               /* x86 can have a finegrained bitmap which indicates what I/O
-                * ports the process can use.  We set it to the end of our
-                * structure, meaning "none". */
-               state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
-
-               /* Some GDT entries are the same across all Guests, so we can
-                * set them up now. */
-               setup_default_gdt_entries(state);
-               /* Most IDT entries are the same for all Guests, too.*/
-               setup_default_idt_entries(state, default_idt_entries);
-
-               /* The Host needs to be able to use the LGUEST segments on this
-                * CPU, too, so put them in the Host GDT. */
-               get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
-               get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
-       }
-
-       /* In the Switcher, we want the %cs segment register to use the
-        * LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
-        * it will be undisturbed when we switch.  To change %cs and jump we
-        * need this structure to feed to Intel's "lcall" instruction. */
-       lguest_entry.offset = (long)switch_to_guest + switcher_offset();
-       lguest_entry.segment = LGUEST_CS;
-
        printk(KERN_INFO "lguest: mapped switcher at %p\n",
               switcher_vma->addr);
        /* And we succeeded... */
@@ -247,86 +128,12 @@ static void unmap_switcher(void)
                __free_pages(switcher_page[i], 0);
 }
 
-/*H:130 Our Guest is usually so well behaved; it never tries to do things it
- * isn't allowed to.  Unfortunately, Linux's paravirtual infrastructure isn't
- * quite complete, because it doesn't contain replacements for the Intel I/O
- * instructions.  As a result, the Guest sometimes fumbles across one during
- * the boot process as it probes for various things which are usually attached
- * to a PC.
- *
- * When the Guest uses one of these instructions, we get trap #13 (General
- * Protection Fault) and come here.  We see if it's one of those troublesome
- * instructions and skip over it.  We return true if we did. */
-static int emulate_insn(struct lguest *lg)
-{
-       u8 insn;
-       unsigned int insnlen = 0, in = 0, shift = 0;
-       /* The eip contains the *virtual* address of the Guest's instruction:
-        * guest_pa just subtracts the Guest's page_offset. */
-       unsigned long physaddr = guest_pa(lg, lg->regs->eip);
-
-       /* The guest_pa() function only works for Guest kernel addresses, but
-        * that's all we're trying to do anyway. */
-       if (lg->regs->eip < lg->page_offset)
-               return 0;
-
-       /* Decoding x86 instructions is icky. */
-       lgread(lg, &insn, physaddr, 1);
-
-       /* 0x66 is an "operand prefix".  It means it's using the upper 16 bits
-          of the eax register. */
-       if (insn == 0x66) {
-               shift = 16;
-               /* The instruction is 1 byte so far, read the next byte. */
-               insnlen = 1;
-               lgread(lg, &insn, physaddr + insnlen, 1);
-       }
-
-       /* We can ignore the lower bit for the moment and decode the 4 opcodes
-        * we need to emulate. */
-       switch (insn & 0xFE) {
-       case 0xE4: /* in     <next byte>,%al */
-               insnlen += 2;
-               in = 1;
-               break;
-       case 0xEC: /* in     (%dx),%al */
-               insnlen += 1;
-               in = 1;
-               break;
-       case 0xE6: /* out    %al,<next byte> */
-               insnlen += 2;
-               break;
-       case 0xEE: /* out    %al,(%dx) */
-               insnlen += 1;
-               break;
-       default:
-               /* OK, we don't know what this is, can't emulate. */
-               return 0;
-       }
-
-       /* If it was an "IN" instruction, they expect the result to be read
-        * into %eax, so we change %eax.  We always return all-ones, which
-        * traditionally means "there's nothing there". */
-       if (in) {
-               /* Lower bit tells is whether it's a 16 or 32 bit access */
-               if (insn & 0x1)
-                       lg->regs->eax = 0xFFFFFFFF;
-               else
-                       lg->regs->eax |= (0xFFFF << shift);
-       }
-       /* Finally, we've "done" the instruction, so move past it. */
-       lg->regs->eip += insnlen;
-       /* Success! */
-       return 1;
-}
-/*:*/
-
 /*L:305
  * Dealing With Guest Memory.
  *
  * When the Guest gives us (what it thinks is) a physical address, we can use
- * the normal copy_from_user() & copy_to_user() on that address: remember,
- * Guest physical == Launcher virtual.
+ * the normal copy_from_user() & copy_to_user() on the corresponding place in
+ * the memory region allocated by the Launcher.
  *
  * But we can't trust the Guest: it might be trying to access the Launcher
  * code.  We have to check that the range is below the pfn_limit the Launcher
@@ -338,148 +145,27 @@ int lguest_address_ok(const struct lguest *lg,
        return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
 }
 
-/* This is a convenient routine to get a 32-bit value from the Guest (a very
- * common operation).  Here we can see how useful the kill_lguest() routine we
- * met in the Launcher can be: we return a random value (0) instead of needing
- * to return an error. */
-u32 lgread_u32(struct lguest *lg, unsigned long addr)
-{
-       u32 val = 0;
-
-       /* Don't let them access lguest binary. */
-       if (!lguest_address_ok(lg, addr, sizeof(val))
-           || get_user(val, (u32 __user *)addr) != 0)
-               kill_guest(lg, "bad read address %#lx", addr);
-       return val;
-}
-
-/* Same thing for writing a value. */
-void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
-{
-       if (!lguest_address_ok(lg, addr, sizeof(val))
-           || put_user(val, (u32 __user *)addr) != 0)
-               kill_guest(lg, "bad write address %#lx", addr);
-}
-
-/* This routine is more generic, and copies a range of Guest bytes into a
- * buffer.  If the copy_from_user() fails, we fill the buffer with zeroes, so
- * the caller doesn't end up using uninitialized kernel memory. */
-void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
+/* This routine copies memory from the Guest.  Here we can see how useful the
+ * kill_lguest() routine we met in the Launcher can be: we return a random
+ * value (all zeroes) instead of needing to return an error. */
+void __lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
 {
        if (!lguest_address_ok(lg, addr, bytes)
-           || copy_from_user(b, (void __user *)addr, bytes) != 0) {
+           || copy_from_user(b, lg->mem_base + addr, bytes) != 0) {
                /* copy_from_user should do this, but as we rely on it... */
                memset(b, 0, bytes);
                kill_guest(lg, "bad read address %#lx len %u", addr, bytes);
        }
 }
 
-/* Similarly, our generic routine to copy into a range of Guest bytes. */
-void lgwrite(struct lguest *lg, unsigned long addr, const void *b,
-            unsigned bytes)
+/* This is the write (copy into guest) version. */
+void __lgwrite(struct lguest *lg, unsigned long addr, const void *b,
+              unsigned bytes)
 {
        if (!lguest_address_ok(lg, addr, bytes)
-           || copy_to_user((void __user *)addr, b, bytes) != 0)
+           || copy_to_user(lg->mem_base + addr, b, bytes) != 0)
                kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
 }
-/* (end of memory access helper routines) :*/
-
-static void set_ts(void)
-{
-       u32 cr0;
-
-       cr0 = read_cr0();
-       if (!(cr0 & 8))
-               write_cr0(cr0|8);
-}
-
-/*S:010
- * We are getting close to the Switcher.
- *
- * Remember that each CPU has two pages which are visible to the Guest when it
- * runs on that CPU.  This has to contain the state for that Guest: we copy the
- * state in just before we run the Guest.
- *
- * Each Guest has "changed" flags which indicate what has changed in the Guest
- * since it last ran.  We saw this set in interrupts_and_traps.c and
- * segments.c.
- */
-static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
-{
-       /* Copying all this data can be quite expensive.  We usually run the
-        * same Guest we ran last time (and that Guest hasn't run anywhere else
-        * meanwhile).  If that's not the case, we pretend everything in the
-        * Guest has changed. */
-       if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
-               __get_cpu_var(last_guest) = lg;
-               lg->last_pages = pages;
-               lg->changed = CHANGED_ALL;
-       }
-
-       /* These copies are pretty cheap, so we do them unconditionally: */
-       /* Save the current Host top-level page directory. */
-       pages->state.host_cr3 = __pa(current->mm->pgd);
-       /* Set up the Guest's page tables to see this CPU's pages (and no
-        * other CPU's pages). */
-       map_switcher_in_guest(lg, pages);
-       /* Set up the two "TSS" members which tell the CPU what stack to use
-        * for traps which do directly into the Guest (ie. traps at privilege
-        * level 1). */
-       pages->state.guest_tss.esp1 = lg->esp1;
-       pages->state.guest_tss.ss1 = lg->ss1;
-
-       /* Copy direct-to-Guest trap entries. */
-       if (lg->changed & CHANGED_IDT)
-               copy_traps(lg, pages->state.guest_idt, default_idt_entries);
-
-       /* Copy all GDT entries which the Guest can change. */
-       if (lg->changed & CHANGED_GDT)
-               copy_gdt(lg, pages->state.guest_gdt);
-       /* If only the TLS entries have changed, copy them. */
-       else if (lg->changed & CHANGED_GDT_TLS)
-               copy_gdt_tls(lg, pages->state.guest_gdt);
-
-       /* Mark the Guest as unchanged for next time. */
-       lg->changed = 0;
-}
-
-/* Finally: the code to actually call into the Switcher to run the Guest. */
-static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
-{
-       /* This is a dummy value we need for GCC's sake. */
-       unsigned int clobber;
-
-       /* Copy the guest-specific information into this CPU's "struct
-        * lguest_pages". */
-       copy_in_guest_info(lg, pages);
-
-       /* Set the trap number to 256 (impossible value).  If we fault while
-        * switching to the Guest (bad segment registers or bug), this will
-        * cause us to abort the Guest. */
-       lg->regs->trapnum = 256;
-
-       /* Now: we push the "eflags" register on the stack, then do an "lcall".
-        * This is how we change from using the kernel code segment to using
-        * the dedicated lguest code segment, as well as jumping into the
-        * Switcher.
-        *
-        * The lcall also pushes the old code segment (KERNEL_CS) onto the
-        * stack, then the address of this call.  This stack layout happens to
-        * exactly match the stack of an interrupt... */
-       asm volatile("pushf; lcall *lguest_entry"
-                    /* This is how we tell GCC that %eax ("a") and %ebx ("b")
-                     * are changed by this routine.  The "=" means output. */
-                    : "=a"(clobber), "=b"(clobber)
-                    /* %eax contains the pages pointer.  ("0" refers to the
-                     * 0-th argument above, ie "a").  %ebx contains the
-                     * physical address of the Guest's top-level page
-                     * directory. */
-                    : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
-                    /* We tell gcc that all these registers could change,
-                     * which means we don't have to save and restore them in
-                     * the Switcher. */
-                    : "memory", "%edx", "%ecx", "%edi", "%esi");
-}
 /*:*/
 
 /*H:030 Let's jump straight to the the main loop which runs the Guest.
@@ -489,22 +175,16 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
 {
        /* We stop running once the Guest is dead. */
        while (!lg->dead) {
-               /* We need to initialize this, otherwise gcc complains.  It's
-                * not (yet) clever enough to see that it's initialized when we
-                * need it. */
-               unsigned int cr2 = 0; /* Damn gcc */
-
-               /* First we run any hypercalls the Guest wants done: either in
-                * the hypercall ring in "struct lguest_data", or directly by
-                * using int 31 (LGUEST_TRAP_ENTRY). */
-               do_hypercalls(lg);
-               /* It's possible the Guest did a SEND_DMA hypercall to the
+               /* First we run any hypercalls the Guest wants done. */
+               if (lg->hcall)
+                       do_hypercalls(lg);
+
+               /* It's possible the Guest did a NOTIFY hypercall to the
                 * Launcher, in which case we return from the read() now. */
-               if (lg->dma_is_pending) {
-                       if (put_user(lg->pending_dma, user) ||
-                           put_user(lg->pending_key, user+1))
+               if (lg->pending_notify) {
+                       if (put_user(lg->pending_notify, user))
                                return -EFAULT;
-                       return sizeof(unsigned long)*2;
+                       return sizeof(lg->pending_notify);
                }
 
                /* Check for signals */
@@ -542,144 +222,20 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
                 * the "Do Not Disturb" sign: */
                local_irq_disable();
 
-               /* Remember the awfully-named TS bit?  If the Guest has asked
-                * to set it we set it now, so we can trap and pass that trap
-                * to the Guest if it uses the FPU. */
-               if (lg->ts)
-                       set_ts();
-
-               /* SYSENTER is an optimized way of doing system calls.  We
-                * can't allow it because it always jumps to privilege level 0.
-                * A normal Guest won't try it because we don't advertise it in
-                * CPUID, but a malicious Guest (or malicious Guest userspace
-                * program) could, so we tell the CPU to disable it before
-                * running the Guest. */
-               if (boot_cpu_has(X86_FEATURE_SEP))
-                       wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
-
-               /* Now we actually run the Guest.  It will pop back out when
-                * something interesting happens, and we can examine its
-                * registers to see what it was doing. */
-               run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
-
-               /* The "regs" pointer contains two extra entries which are not
-                * really registers: a trap number which says what interrupt or
-                * trap made the switcher code come back, and an error code
-                * which some traps set.  */
-
-               /* If the Guest page faulted, then the cr2 register will tell
-                * us the bad virtual address.  We have to grab this now,
-                * because once we re-enable interrupts an interrupt could
-                * fault and thus overwrite cr2, or we could even move off to a
-                * different CPU. */
-               if (lg->regs->trapnum == 14)
-                       cr2 = read_cr2();
-               /* Similarly, if we took a trap because the Guest used the FPU,
-                * we have to restore the FPU it expects to see. */
-               else if (lg->regs->trapnum == 7)
-                       math_state_restore();
-
-               /* Restore SYSENTER if it's supposed to be on. */
-               if (boot_cpu_has(X86_FEATURE_SEP))
-                       wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+               /* Actually run the Guest until something happens. */
+               lguest_arch_run_guest(lg);
 
                /* Now we're ready to be interrupted or moved to other CPUs */
                local_irq_enable();
 
-               /* OK, so what happened? */
-               switch (lg->regs->trapnum) {
-               case 13: /* We've intercepted a GPF. */
-                       /* Check if this was one of those annoying IN or OUT
-                        * instructions which we need to emulate.  If so, we
-                        * just go back into the Guest after we've done it. */
-                       if (lg->regs->errcode == 0) {
-                               if (emulate_insn(lg))
-                                       continue;
-                       }
-                       break;
-               case 14: /* We've intercepted a page fault. */
-                       /* The Guest accessed a virtual address that wasn't
-                        * mapped.  This happens a lot: we don't actually set
-                        * up most of the page tables for the Guest at all when
-                        * we start: as it runs it asks for more and more, and
-                        * we set them up as required. In this case, we don't
-                        * even tell the Guest that the fault happened.
-                        *
-                        * The errcode tells whether this was a read or a
-                        * write, and whether kernel or userspace code. */
-                       if (demand_page(lg, cr2, lg->regs->errcode))
-                               continue;
-
-                       /* OK, it's really not there (or not OK): the Guest
-                        * needs to know.  We write out the cr2 value so it
-                        * knows where the fault occurred.
-                        *
-                        * Note that if the Guest were really messed up, this
-                        * could happen before it's done the INITIALIZE
-                        * hypercall, so lg->lguest_data will be NULL, so
-                        * &lg->lguest_data->cr2 will be address 8.  Writing
-                        * into that address won't hurt the Host at all,
-                        * though. */
-                       if (put_user(cr2, &lg->lguest_data->cr2))
-                               kill_guest(lg, "Writing cr2");
-                       break;
-               case 7: /* We've intercepted a Device Not Available fault. */
-                       /* If the Guest doesn't want to know, we already
-                        * restored the Floating Point Unit, so we just
-                        * continue without telling it. */
-                       if (!lg->ts)
-                               continue;
-                       break;
-               case 32 ... 255:
-                       /* These values mean a real interrupt occurred, in
-                        * which case the Host handler has already been run.
-                        * We just do a friendly check if another process
-                        * should now be run, then fall through to loop
-                        * around: */
-                       cond_resched();
-               case LGUEST_TRAP_ENTRY: /* Handled at top of loop */
-                       continue;
-               }
-
-               /* If we get here, it's a trap the Guest wants to know
-                * about. */
-               if (deliver_trap(lg, lg->regs->trapnum))
-                       continue;
-
-               /* If the Guest doesn't have a handler (either it hasn't
-                * registered any yet, or it's one of the faults we don't let
-                * it handle), it dies with a cryptic error message. */
-               kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
-                          lg->regs->trapnum, lg->regs->eip,
-                          lg->regs->trapnum == 14 ? cr2 : lg->regs->errcode);
+               /* Now we deal with whatever happened to the Guest. */
+               lguest_arch_handle_trap(lg);
        }
+
        /* The Guest is dead => "No such file or directory" */
        return -ENOENT;
 }
 
-/* Now we can look at each of the routines this calls, in increasing order of
- * complexity: do_hypercalls(), emulate_insn(), maybe_do_interrupt(),
- * deliver_trap() and demand_page().  After all those, we'll be ready to
- * examine the Switcher, and our philosophical understanding of the Host/Guest
- * duality will be complete. :*/
-
-int find_free_guest(void)
-{
-       unsigned int i;
-       for (i = 0; i < MAX_LGUEST_GUESTS; i++)
-               if (!lguests[i].tsk)
-                       return i;
-       return -1;
-}
-
-static void adjust_pge(void *on)
-{
-       if (on)
-               write_cr4(read_cr4() | X86_CR4_PGE);
-       else
-               write_cr4(read_cr4() & ~X86_CR4_PGE);
-}
-
 /*H:000
  * Welcome to the Host!
  *
@@ -701,72 +257,50 @@ static int __init init(void)
        /* First we put the Switcher up in very high virtual memory. */
        err = map_switcher();
        if (err)
-               return err;
+               goto out;
 
        /* Now we set up the pagetable implementation for the Guests. */
        err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES);
-       if (err) {
-               unmap_switcher();
-               return err;
-       }
+       if (err)
+               goto unmap;
 
-       /* The I/O subsystem needs some things initialized. */
-       lguest_io_init();
+       /* We might need to reserve an interrupt vector. */
+       err = init_interrupts();
+       if (err)
+               goto free_pgtables;
 
        /* /dev/lguest needs to be registered. */
        err = lguest_device_init();
-       if (err) {
-               free_pagetables();
-               unmap_switcher();
-               return err;
-       }
+       if (err)
+               goto free_interrupts;
 
-       /* Finally, we need to turn off "Page Global Enable".  PGE is an
-        * optimization where page table entries are specially marked to show
-        * they never change.  The Host kernel marks all the kernel pages this
-        * way because it's always present, even when userspace is running.
-        *
-        * Lguest breaks this: unbeknownst to the rest of the Host kernel, we
-        * switch to the Guest kernel.  If you don't disable this on all CPUs,
-        * you'll get really weird bugs that you'll chase for two days.
-        *
-        * I used to turn PGE off every time we switched to the Guest and back
-        * on when we return, but that slowed the Switcher down noticibly. */
-
-       /* We don't need the complexity of CPUs coming and going while we're
-        * doing this. */
-       lock_cpu_hotplug();
-       if (cpu_has_pge) { /* We have a broader idea of "global". */
-               /* Remember that this was originally set (for cleanup). */
-               cpu_had_pge = 1;
-               /* adjust_pge is a helper function which sets or unsets the PGE
-                * bit on its CPU, depending on the argument (0 == unset). */
-               on_each_cpu(adjust_pge, (void *)0, 0, 1);
-               /* Turn off the feature in the global feature set. */
-               clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
-       }
-       unlock_cpu_hotplug();
+       /* Finally we do some architecture-specific setup. */
+       lguest_arch_host_init();
 
        /* All good! */
        return 0;
+
+free_interrupts:
+       free_interrupts();
+free_pgtables:
+       free_pagetables();
+unmap:
+       unmap_switcher();
+out:
+       return err;
 }
 
 /* Cleaning up is just the same code, backwards.  With a little French. */
 static void __exit fini(void)
 {
        lguest_device_remove();
+       free_interrupts();
        free_pagetables();
        unmap_switcher();
 
-       /* If we had PGE before we started, turn it back on now. */
-       lock_cpu_hotplug();
-       if (cpu_had_pge) {
-               set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
-               /* adjust_pge's argument "1" means set PGE. */
-               on_each_cpu(adjust_pge, (void *)1, 0, 1);
-       }
-       unlock_cpu_hotplug();
+       lguest_arch_host_fini();
 }
+/*:*/
 
 /* The Host side of lguest can be a module.  This is a nice way for people to
  * play with it.  */
index db6caac..9d5184c 100644 (file)
 #include <linux/mm.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <irq_vectors.h>
 #include "lg.h"
 
-/*H:120 This is the core hypercall routine: where the Guest gets what it
- * wants.  Or gets killed.  Or, in the case of LHCALL_CRASH, both.
- *
- * Remember from the Guest: %eax == which call to make, and the arguments are
- * packed into %edx, %ebx and %ecx if needed. */
-static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
+/*H:120 This is the core hypercall routine: where the Guest gets what it wants.
+ * Or gets killed.  Or, in the case of LHCALL_CRASH, both. */
+static void do_hcall(struct lguest *lg, struct hcall_args *args)
 {
-       switch (regs->eax) {
+       switch (args->arg0) {
        case LHCALL_FLUSH_ASYNC:
                /* This call does nothing, except by breaking out of the Guest
                 * it makes us process all the asynchronous hypercalls. */
@@ -51,7 +47,7 @@ static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
                char msg[128];
                /* If the lgread fails, it will call kill_guest() itself; the
                 * kill_guest() with the message will be ignored. */
-               lgread(lg, msg, regs->edx, sizeof(msg));
+               __lgread(lg, msg, args->arg1, sizeof(msg));
                msg[sizeof(msg)-1] = '\0';
                kill_guest(lg, "CRASH: %s", msg);
                break;
@@ -59,67 +55,49 @@ static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
        case LHCALL_FLUSH_TLB:
                /* FLUSH_TLB comes in two flavors, depending on the
                 * argument: */
-               if (regs->edx)
+               if (args->arg1)
                        guest_pagetable_clear_all(lg);
                else
                        guest_pagetable_flush_user(lg);
                break;
-       case LHCALL_BIND_DMA:
-               /* BIND_DMA really wants four arguments, but it's the only call
-                * which does.  So the Guest packs the number of buffers and
-                * the interrupt number into the final argument, and we decode
-                * it here.  This can legitimately fail, since we currently
-                * place a limit on the number of DMA pools a Guest can have.
-                * So we return true or false from this call. */
-               regs->eax = bind_dma(lg, regs->edx, regs->ebx,
-                                    regs->ecx >> 8, regs->ecx & 0xFF);
-               break;
 
        /* All these calls simply pass the arguments through to the right
         * routines. */
-       case LHCALL_SEND_DMA:
-               send_dma(lg, regs->edx, regs->ebx);
-               break;
-       case LHCALL_LOAD_GDT:
-               load_guest_gdt(lg, regs->edx, regs->ebx);
-               break;
-       case LHCALL_LOAD_IDT_ENTRY:
-               load_guest_idt_entry(lg, regs->edx, regs->ebx, regs->ecx);
-               break;
        case LHCALL_NEW_PGTABLE:
-               guest_new_pagetable(lg, regs->edx);
+               guest_new_pagetable(lg, args->arg1);
                break;
        case LHCALL_SET_STACK:
-               guest_set_stack(lg, regs->edx, regs->ebx, regs->ecx);
+               guest_set_stack(lg, args->arg1, args->arg2, args->arg3);
                break;
        case LHCALL_SET_PTE:
-               guest_set_pte(lg, regs->edx, regs->ebx, mkgpte(regs->ecx));
+               guest_set_pte(lg, args->arg1, args->arg2, __pte(args->arg3));
                break;
        case LHCALL_SET_PMD:
-               guest_set_pmd(lg, regs->edx, regs->ebx);
-               break;
-       case LHCALL_LOAD_TLS:
-               guest_load_tls(lg, regs->edx);
+               guest_set_pmd(lg, args->arg1, args->arg2);
                break;
        case LHCALL_SET_CLOCKEVENT:
-               guest_set_clockevent(lg, regs->edx);
+               guest_set_clockevent(lg, args->arg1);
                break;
-
        case LHCALL_TS:
                /* This sets the TS flag, as we saw used in run_guest(). */
-               lg->ts = regs->edx;
+               lg->ts = args->arg1;
                break;
        case LHCALL_HALT:
                /* Similarly, this sets the halted flag for run_guest(). */
                lg->halted = 1;
                break;
+       case LHCALL_NOTIFY:
+               lg->pending_notify = args->arg1;
+               break;
        default:
-               kill_guest(lg, "Bad hypercall %li\n", regs->eax);
+               if (lguest_arch_do_hcall(lg, args))
+                       kill_guest(lg, "Bad hypercall %li\n", args->arg0);
        }
 }
+/*:*/
 
-/* Asynchronous hypercalls are easy: we just look in the array in the Guest's
- * "struct lguest_data" and see if there are any new ones marked "ready".
+/*H:124 Asynchronous hypercalls are easy: we just look in the array in the
+ * Guest's "struct lguest_data" to see if any new ones are marked "ready".
  *
  * We are careful to do these in order: obviously we respect the order the
  * Guest put them in the ring, but we also promise the Guest that they will
@@ -134,10 +112,9 @@ static void do_async_hcalls(struct lguest *lg)
        if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st)))
                return;
 
-
        /* We process "struct lguest_data"s hcalls[] ring once. */
        for (i = 0; i < ARRAY_SIZE(st); i++) {
-               struct lguest_regs regs;
+               struct hcall_args args;
                /* We remember where we were up to from last time.  This makes
                 * sure that the hypercalls are done in the order the Guest
                 * places them in the ring. */
@@ -152,18 +129,16 @@ static void do_async_hcalls(struct lguest *lg)
                if (++lg->next_hcall == LHCALL_RING_SIZE)
                        lg->next_hcall = 0;
 
-               /* We copy the hypercall arguments into a fake register
-                * structure.  This makes life simple for do_hcall(). */
-               if (get_user(regs.eax, &lg->lguest_data->hcalls[n].eax)
-                   || get_user(regs.edx, &lg->lguest_data->hcalls[n].edx)
-                   || get_user(regs.ecx, &lg->lguest_data->hcalls[n].ecx)
-                   || get_user(regs.ebx, &lg->lguest_data->hcalls[n].ebx)) {
+               /* Copy the hypercall arguments into a local copy of
+                * the hcall_args struct. */
+               if (copy_from_user(&args, &lg->lguest_data->hcalls[n],
+                                  sizeof(struct hcall_args))) {
                        kill_guest(lg, "Fetching async hypercalls");
                        break;
                }
 
                /* Do the hypercall, same as a normal one. */
-               do_hcall(lg, &regs);
+               do_hcall(lg, &args);
 
                /* Mark the hypercall done. */
                if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) {
@@ -171,9 +146,9 @@ static void do_async_hcalls(struct lguest *lg)
                        break;
                }
 
-               /* Stop doing hypercalls if we've just done a DMA to the
-                * Launcher: it needs to service this first. */
-               if (lg->dma_is_pending)
+               /* Stop doing hypercalls if they want to notify the Launcher:
+                * it needs to service this first. */
+               if (lg->pending_notify)
                        break;
        }
 }
@@ -182,76 +157,35 @@ static void do_async_hcalls(struct lguest *lg)
  * Guest makes a hypercall, we end up here to set things up: */
 static void initialize(struct lguest *lg)
 {
-       u32 tsc_speed;
 
        /* You can't do anything until you're initialized.  The Guest knows the
         * rules, so we're unforgiving here. */
-       if (lg->regs->eax != LHCALL_LGUEST_INIT) {
-               kill_guest(lg, "hypercall %li before LGUEST_INIT",
-                          lg->regs->eax);
+       if (lg->hcall->arg0 != LHCALL_LGUEST_INIT) {
+               kill_guest(lg, "hypercall %li before INIT", lg->hcall->arg0);
                return;
        }
 
-       /* We insist that the Time Stamp Counter exist and doesn't change with
-        * cpu frequency.  Some devious chip manufacturers decided that TSC
-        * changes could be handled in software.  I decided that time going
-        * backwards might be good for benchmarks, but it's bad for users.
-        *
-        * We also insist that the TSC be stable: the kernel detects unreliable
-        * TSCs for its own purposes, and we use that here. */
-       if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
-               tsc_speed = tsc_khz;
-       else
-               tsc_speed = 0;
-
-       /* The pointer to the Guest's "struct lguest_data" is the only
-        * argument. */
-       lg->lguest_data = (struct lguest_data __user *)lg->regs->edx;
-       /* If we check the address they gave is OK now, we can simply
-        * copy_to_user/from_user from now on rather than using lgread/lgwrite.
-        * I put this in to show that I'm not immune to writing stupid
-        * optimizations. */
-       if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) {
+       if (lguest_arch_init_hypercalls(lg))
                kill_guest(lg, "bad guest page %p", lg->lguest_data);
-               return;
-       }
+
        /* The Guest tells us where we're not to deliver interrupts by putting
         * the range of addresses into "struct lguest_data". */
        if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start)
-           || get_user(lg->noirq_end, &lg->lguest_data->noirq_end)
-           /* We tell the Guest that it can't use the top 4MB of virtual
-            * addresses used by the Switcher. */
-           || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
-           || put_user(tsc_speed, &lg->lguest_data->tsc_khz)
-           /* We also give the Guest a unique id, as used in lguest_net.c. */
-           || put_user(lg->guestid, &lg->lguest_data->guestid))
+           || get_user(lg->noirq_end, &lg->lguest_data->noirq_end))
                kill_guest(lg, "bad guest page %p", lg->lguest_data);
 
        /* We write the current time into the Guest's data page once now. */
        write_timestamp(lg);
 
+       /* page_tables.c will also do some setup. */
+       page_table_guest_data_init(lg);
+
        /* This is the one case where the above accesses might have been the
         * first write to a Guest page.  This may have caused a copy-on-write
         * fault, but the Guest might be referring to the old (read-only)
         * page. */
        guest_pagetable_clear_all(lg);
 }
-/* Now we've examined the hypercall code; our Guest can make requests.  There
- * is one other way we can do things for the Guest, as we see in
- * emulate_insn(). */
-
-/*H:110 Tricky point: we mark the hypercall as "done" once we've done it.
- * Normally we don't need to do this: the Guest will run again and update the
- * trap number before we come back around the run_guest() loop to
- * do_hypercalls().
- *
- * However, if we are signalled or the Guest sends DMA to the Launcher, that
- * loop will exit without running the Guest.  When it comes back it would try
- * to re-run the hypercall. */
-static void clear_hcall(struct lguest *lg)
-{
-       lg->regs->trapnum = 255;
-}
 
 /*H:100
  * Hypercalls
@@ -261,16 +195,12 @@ static void clear_hcall(struct lguest *lg)
  */
 void do_hypercalls(struct lguest *lg)
 {
-       /* Not initialized yet? */
+       /* Not initialized yet?  This hypercall must do it. */
        if (unlikely(!lg->lguest_data)) {
-               /* Did the Guest make a hypercall?  We might have come back for
-                * some other reason (an interrupt, a different trap). */
-               if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
-                       /* Set up the "struct lguest_data" */
-                       initialize(lg);
-                       /* The hypercall is done. */
-                       clear_hcall(lg);
-               }
+               /* Set up the "struct lguest_data" */
+               initialize(lg);
+               /* Hcall is done. */
+               lg->hcall = NULL;
                return;
        }
 
@@ -280,12 +210,21 @@ void do_hypercalls(struct lguest *lg)
        do_async_hcalls(lg);
 
        /* If we stopped reading the hypercall ring because the Guest did a
-        * SEND_DMA to the Launcher, we want to return now.  Otherwise if the
-        * Guest asked us to do a hypercall, we do it. */
-       if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
-               do_hcall(lg, lg->regs);
-               /* The hypercall is done. */
-               clear_hcall(lg);
+        * NOTIFY to the Launcher, we want to return now.  Otherwise we do
+        * the hypercall. */
+       if (!lg->pending_notify) {
+               do_hcall(lg, lg->hcall);
+               /* Tricky point: we reset the hcall pointer to mark the
+                * hypercall as "done".  We use the hcall pointer rather than
+                * the trap number to indicate a hypercall is pending.
+                * Normally it doesn't matter: the Guest will run again and
+                * update the trap number before we come back here.
+                *
+                * However, if we are signalled or the Guest sends DMA to the
+                * Launcher, the run_guest() loop will exit without running the
+                * Guest.  When it comes back it would try to re-run the
+                * hypercall. */
+               lg->hcall = NULL;
        }
 }
 
@@ -295,6 +234,6 @@ void write_timestamp(struct lguest *lg)
 {
        struct timespec now;
        ktime_get_real_ts(&now);
-       if (put_user(now, &lg->lguest_data->time))
+       if (copy_to_user(&lg->lguest_data->time, &now, sizeof(struct timespec)))
                kill_guest(lg, "Writing timestamp");
 }
index 3973123..8296698 100644 (file)
  * them first, so we also have a way of "reflecting" them into the Guest as if
  * they had been delivered to it directly. :*/
 #include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
 #include "lg.h"
 
+/* Allow Guests to use a non-128 (ie. non-Linux) syscall trap. */
+static unsigned int syscall_vector = SYSCALL_VECTOR;
+module_param(syscall_vector, uint, 0444);
+
 /* The address of the interrupt handler is split into two bits: */
 static unsigned long idt_address(u32 lo, u32 hi)
 {
@@ -39,7 +45,7 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
 {
        /* Stack grows upwards: move stack then write value. */
        *gstack -= 4;
-       lgwrite_u32(lg, *gstack, val);
+       lgwrite(lg, *gstack, u32, val);
 }
 
 /*H:210 The set_guest_interrupt() routine actually delivers the interrupt or
@@ -56,8 +62,9 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
  * it). */
 static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
 {
-       unsigned long gstack;
+       unsigned long gstack, origstack;
        u32 eflags, ss, irq_enable;
+       unsigned long virtstack;
 
        /* There are two cases for interrupts: one where the Guest is already
         * in the kernel, and a more complex one where the Guest is in
@@ -65,8 +72,10 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
        if ((lg->regs->ss&0x3) != GUEST_PL) {
                /* The Guest told us their kernel stack with the SET_STACK
                 * hypercall: both the virtual address and the segment */
-               gstack = guest_pa(lg, lg->esp1);
+               virtstack = lg->esp1;
                ss = lg->ss1;
+
+               origstack = gstack = guest_pa(lg, virtstack);
                /* We push the old stack segment and pointer onto the new
                 * stack: when the Guest does an "iret" back from the interrupt
                 * handler the CPU will notice they're dropping privilege
@@ -75,8 +84,10 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
                push_guest_stack(lg, &gstack, lg->regs->esp);
        } else {
                /* We're staying on the same Guest (kernel) stack. */
-               gstack = guest_pa(lg, lg->regs->esp);
+               virtstack = lg->regs->esp;
                ss = lg->regs->ss;
+
+               origstack = gstack = guest_pa(lg, virtstack);
        }
 
        /* Remember that we never let the Guest actually disable interrupts, so
@@ -102,7 +113,7 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
        /* Now we've pushed all the old state, we change the stack, the code
         * segment and the address to execute. */
        lg->regs->ss = ss;
-       lg->regs->esp = gstack + lg->page_offset;
+       lg->regs->esp = virtstack + (gstack - origstack);
        lg->regs->cs = (__KERNEL_CS|GUEST_PL);
        lg->regs->eip = idt_address(lo, hi);
 
@@ -165,7 +176,7 @@ void maybe_do_interrupt(struct lguest *lg)
        /* Look at the IDT entry the Guest gave us for this interrupt.  The
         * first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip
         * over them. */
-       idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq];
+       idt = &lg->arch.idt[FIRST_EXTERNAL_VECTOR+irq];
        /* If they don't have a handler (yet?), we just ignore it */
        if (idt_present(idt->a, idt->b)) {
                /* OK, mark it no longer pending and deliver it. */
@@ -183,6 +194,47 @@ void maybe_do_interrupt(struct lguest *lg)
         * timer interrupt. */
        write_timestamp(lg);
 }
+/*:*/
+
+/* Linux uses trap 128 for system calls.  Plan9 uses 64, and Ron Minnich sent
+ * me a patch, so we support that too.  It'd be a big step for lguest if half
+ * the Plan 9 user base were to start using it.
+ *
+ * Actually now I think of it, it's possible that Ron *is* half the Plan 9
+ * userbase.  Oh well. */
+static bool could_be_syscall(unsigned int num)
+{
+       /* Normal Linux SYSCALL_VECTOR or reserved vector? */
+       return num == SYSCALL_VECTOR || num == syscall_vector;
+}
+
+/* The syscall vector it wants must be unused by Host. */
+bool check_syscall_vector(struct lguest *lg)
+{
+       u32 vector;
+
+       if (get_user(vector, &lg->lguest_data->syscall_vec))
+               return false;
+
+       return could_be_syscall(vector);
+}
+
+int init_interrupts(void)
+{
+       /* If they want some strange system call vector, reserve it now */
+       if (syscall_vector != SYSCALL_VECTOR
+           && test_and_set_bit(syscall_vector, used_vectors)) {
+               printk("lg: couldn't reserve syscall %u\n", syscall_vector);
+               return -EBUSY;
+       }
+       return 0;
+}
+
+void free_interrupts(void)
+{
+       if (syscall_vector != SYSCALL_VECTOR)
+               clear_bit(syscall_vector, used_vectors);
+}
 
 /*H:220 Now we've got the routines to deliver interrupts, delivering traps
  * like page fault is easy.  The only trick is that Intel decided that some
@@ -197,14 +249,14 @@ int deliver_trap(struct lguest *lg, unsigned int num)
 {
        /* Trap numbers are always 8 bit, but we set an impossible trap number
         * for traps inside the Switcher, so check that here. */
-       if (num >= ARRAY_SIZE(lg->idt))
+       if (num >= ARRAY_SIZE(lg->arch.idt))
                return 0;
 
        /* Early on the Guest hasn't set the IDT entries (or maybe it put a
         * bogus one in): if we fail here, the Guest will be killed. */
-       if (!idt_present(lg->idt[num].a, lg->idt[num].b))
+       if (!idt_present(lg->arch.idt[num].a, lg->arch.idt[num].b))
                return 0;
-       set_guest_interrupt(lg, lg->idt[num].a, lg->idt[num].b, has_err(num));
+       set_guest_interrupt(lg, lg->arch.idt[num].a, lg->arch.idt[num].b, has_err(num));
        return 1;
 }
 
@@ -218,28 +270,20 @@ int deliver_trap(struct lguest *lg, unsigned int num)
  * system calls down from 1750ns to 270ns.  Plus, if lguest didn't do it, all
  * the other hypervisors would tease it.
  *
- * This routine determines if a trap can be delivered directly. */
-static int direct_trap(const struct lguest *lg,
-                      const struct desc_struct *trap,
-                      unsigned int num)
+ * This routine indicates if a particular trap number could be delivered
+ * directly. */
+static int direct_trap(unsigned int num)
 {
        /* Hardware interrupts don't go to the Guest at all (except system
         * call). */
-       if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR)
+       if (num >= FIRST_EXTERNAL_VECTOR && !could_be_syscall(num))
                return 0;
 
        /* The Host needs to see page faults (for shadow paging and to save the
         * fault address), general protection faults (in/out emulation) and
         * device not available (TS handling), and of course, the hypercall
         * trap. */
-       if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY)
-               return 0;
-
-       /* Only trap gates (type 15) can go direct to the Guest.  Interrupt
-        * gates (type 14) disable interrupts as they are entered, which we
-        * never let the Guest do.  Not present entries (type 0x0) also can't
-        * go direct, of course 8) */
-       return idt_type(trap->a, trap->b) == 0xF;
+       return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY;
 }
 /*:*/
 
@@ -348,15 +392,11 @@ void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
         * to copy this again. */
        lg->changed |= CHANGED_IDT;
 
-       /* The IDT which we keep in "struct lguest" only contains 32 entries
-        * for the traps and LGUEST_IRQS (32) entries for interrupts.  We
-        * ignore attempts to set handlers for higher interrupt numbers, except
-        * for the system call "interrupt" at 128: we have a special IDT entry
-        * for that. */
-       if (num < ARRAY_SIZE(lg->idt))
-               set_trap(lg, &lg->idt[num], num, lo, hi);
-       else if (num == SYSCALL_VECTOR)
-               set_trap(lg, &lg->syscall_idt, num, lo, hi);
+       /* Check that the Guest doesn't try to step outside the bounds. */
+       if (num >= ARRAY_SIZE(lg->arch.idt))
+               kill_guest(lg, "Setting idt entry %u", num);
+       else
+               set_trap(lg, &lg->arch.idt[num], num, lo, hi);
 }
 
 /* The default entry for each interrupt points into the Switcher routines which
@@ -399,20 +439,21 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt,
 
        /* We can simply copy the direct traps, otherwise we use the default
         * ones in the Switcher: they will return to the Host. */
-       for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) {
-               if (direct_trap(lg, &lg->idt[i], i))
-                       idt[i] = lg->idt[i];
+       for (i = 0; i < ARRAY_SIZE(lg->arch.idt); i++) {
+               /* If no Guest can ever override this trap, leave it alone. */
+               if (!direct_trap(i))
+                       continue;
+
+               /* Only trap gates (type 15) can go direct to the Guest.
+                * Interrupt gates (type 14) disable interrupts as they are
+                * entered, which we never let the Guest do.  Not present
+                * entries (type 0x0) also can't go direct, of course. */
+               if (idt_type(lg->arch.idt[i].a, lg->arch.idt[i].b) == 0xF)
+                       idt[i] = lg->arch.idt[i];
                else
+                       /* Reset it to the default. */
                        default_idt_entry(&idt[i], i, def[i]);
        }
-
-       /* Don't forget the system call trap!  The IDT entries for other
-        * interupts never change, so no need to copy them. */
-       i = SYSCALL_VECTOR;
-       if (direct_trap(lg, &lg->syscall_idt, i))
-               idt[i] = lg->syscall_idt;
-       else
-               default_idt_entry(&idt[i], i, def[i]);
 }
 
 void guest_set_clockevent(struct lguest *lg, unsigned long delta)
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c
deleted file mode 100644 (file)
index ea68613..0000000
+++ /dev/null
@@ -1,626 +0,0 @@
-/*P:300 The I/O mechanism in lguest is simple yet flexible, allowing the Guest
- * to talk to the Launcher or directly to another Guest.  It uses familiar
- * concepts of DMA and interrupts, plus some neat code stolen from
- * futexes... :*/
-
-/* Copyright (C) 2006 Rusty Russell IBM Corporation
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- */
-#include <linux/types.h>
-#include <linux/futex.h>
-#include <linux/jhash.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/uaccess.h>
-#include "lg.h"
-
-/*L:300
- * I/O
- *
- * Getting data in and out of the Guest is quite an art.  There are numerous
- * ways to do it, and they all suck differently.  We try to keep things fairly
- * close to "real" hardware so our Guest's drivers don't look like an alien
- * visitation in the middle of the Linux code, and yet make sure that Guests
- * can talk directly to other Guests, not just the Launcher.
- *
- * To do this, the Guest gives us a key when it binds or sends DMA buffers.
- * The key corresponds to a "physical" address inside the Guest (ie. a virtual
- * address inside the Launcher process).  We don't, however, use this key
- * directly.
- *
- * We want Guests which share memory to be able to DMA to each other: two
- * Launchers can mmap memory the same file, then the Guests can communicate.
- * Fortunately, the futex code provides us with a way to get a "union
- * futex_key" corresponding to the memory lying at a virtual address: if the
- * two processes share memory, the "union futex_key" for that memory will match
- * even if the memory is mapped at different addresses in each.  So we always
- * convert the keys to "union futex_key"s to compare them.
- *
- * Before we dive into this though, we need to look at another set of helper
- * routines used throughout the Host kernel code to access Guest memory.
- :*/
-static struct list_head dma_hash[61];
-
-/* An unfortunate side effect of the Linux double-linked list implementation is
- * that there's no good way to statically initialize an array of linked
- * lists. */
-void lguest_io_init(void)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(dma_hash); i++)
-               INIT_LIST_HEAD(&dma_hash[i]);
-}
-
-/* FIXME: allow multi-page lengths. */
-static int check_dma_list(struct lguest *lg, const struct lguest_dma *dma)
-{
-       unsigned int i;
-
-       for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
-               if (!dma->len[i])
-                       return 1;
-               if (!lguest_address_ok(lg, dma->addr[i], dma->len[i]))
-                       goto kill;
-               if (dma->len[i] > PAGE_SIZE)
-                       goto kill;
-               /* We could do over a page, but is it worth it? */
-               if ((dma->addr[i] % PAGE_SIZE) + dma->len[i] > PAGE_SIZE)
-                       goto kill;
-       }
-       return 1;
-
-kill:
-       kill_guest(lg, "bad DMA entry: %u@%#lx", dma->len[i], dma->addr[i]);
-       return 0;
-}
-
-/*L:330 This is our hash function, using the wonderful Jenkins hash.
- *
- * The futex key is a union with three parts: an unsigned long word, a pointer,
- * and an int "offset".  We could use jhash_2words() which takes three u32s.
- * (Ok, the hash functions are great: the naming sucks though).
- *
- * It's nice to be portable to 64-bit platforms, so we use the more generic
- * jhash2(), which takes an array of u32, the number of u32s, and an initial
- * u32 to roll in.  This is uglier, but breaks down to almost the same code on
- * 32-bit platforms like this one.
- *
- * We want a position in the array, so we modulo ARRAY_SIZE(dma_hash) (ie. 61).
- */
-static unsigned int hash(const union futex_key *key)
-{
-       return jhash2((u32*)&key->both.word,
-                     (sizeof(key->both.word)+sizeof(key->both.ptr))/4,
-                     key->both.offset)
-               % ARRAY_SIZE(dma_hash);
-}
-
-/* This is a convenience routine to compare two keys.  It's a much bemoaned C
- * weakness that it doesn't allow '==' on structures or unions, so we have to
- * open-code it like this. */
-static inline int key_eq(const union futex_key *a, const union futex_key *b)
-{
-       return (a->both.word == b->both.word
-               && a->both.ptr == b->both.ptr
-               && a->both.offset == b->both.offset);
-}
-
-/*L:360 OK, when we need to actually free up a Guest's DMA array we do several
- * things, so we have a convenient function to do it.
- *
- * The caller must hold a read lock on dmainfo owner's current->mm->mmap_sem
- * for the drop_futex_key_refs(). */
-static void unlink_dma(struct lguest_dma_info *dmainfo)
-{
-       /* You locked this too, right? */
-       BUG_ON(!mutex_is_locked(&lguest_lock));
-       /* This is how we know that the entry is free. */
-       dmainfo->interrupt = 0;
-       /* Remove it from the hash table. */
-       list_del(&dmainfo->list);
-       /* Drop the references we were holding (to the inode or mm). */
-       drop_futex_key_refs(&dmainfo->key);
-}
-
-/*L:350 This is the routine which we call when the Guest asks to unregister a
- * DMA array attached to a given key.  Returns true if the array was found. */
-static int unbind_dma(struct lguest *lg,
-                     const union futex_key *key,
-                     unsigned long dmas)
-{
-       int i, ret = 0;
-
-       /* We don't bother with the hash table, just look through all this
-        * Guest's DMA arrays. */
-       for (i = 0; i < LGUEST_MAX_DMA; i++) {
-               /* In theory it could have more than one array on the same key,
-                * or one array on multiple keys, so we check both */
-               if (key_eq(key, &lg->dma[i].key) && dmas == lg->dma[i].dmas) {
-                       unlink_dma(&lg->dma[i]);
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
-
-/*L:340 BIND_DMA: this is the hypercall which sets up an array of "struct
- * lguest_dma" for receiving I/O.
- *
- * The Guest wants to bind an array of "struct lguest_dma"s to a particular key
- * to receive input.  This only happens when the Guest is setting up a new
- * device, so it doesn't have to be very fast.
- *
- * It returns 1 on a successful registration (it can fail if we hit the limit
- * of registrations for this Guest).
- */
-int bind_dma(struct lguest *lg,
-            unsigned long ukey, unsigned long dmas, u16 numdmas, u8 interrupt)
-{
-       unsigned int i;
-       int ret = 0;
-       union futex_key key;
-       /* Futex code needs the mmap_sem. */
-       struct rw_semaphore *fshared = &current->mm->mmap_sem;
-
-       /* Invalid interrupt?  (We could kill the guest here). */
-       if (interrupt >= LGUEST_IRQS)
-               return 0;
-
-       /* We need to grab the Big Lguest Lock, because other Guests may be
-        * trying to look through this Guest's DMAs to send something while
-        * we're doing this. */
-       mutex_lock(&lguest_lock);
-       down_read(fshared);
-       if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
-               kill_guest(lg, "bad dma key %#lx", ukey);
-               goto unlock;
-       }
-
-       /* We want to keep this key valid once we drop mmap_sem, so we have to
-        * hold a reference. */
-       get_futex_key_refs(&key);
-
-       /* If the Guest specified an interrupt of 0, that means they want to
-        * unregister this array of "struct lguest_dma"s. */
-       if (interrupt == 0)
-               ret = unbind_dma(lg, &key, dmas);
-       else {
-               /* Look through this Guest's dma array for an unused entry. */
-               for (i = 0; i < LGUEST_MAX_DMA; i++) {
-                       /* If the interrupt is non-zero, the entry is already
-                        * used. */
-                       if (lg->dma[i].interrupt)
-                               continue;
-
-                       /* OK, a free one!  Fill on our details. */
-                       lg->dma[i].dmas = dmas;
-                       lg->dma[i].num_dmas = numdmas;
-                       lg->dma[i].next_dma = 0;
-                       lg->dma[i].key = key;
-                       lg->dma[i].guestid = lg->guestid;
-                       lg->dma[i].interrupt = interrupt;
-
-                       /* Now we add it to the hash table: the position
-                        * depends on the futex key that we got. */
-                       list_add(&lg->dma[i].list, &dma_hash[hash(&key)]);
-                       /* Success! */
-                       ret = 1;
-                       goto unlock;
-               }
-       }
-       /* If we didn't find a slot to put the key in, drop the reference
-        * again. */
-       drop_futex_key_refs(&key);
-unlock:
-       /* Unlock and out. */
-       up_read(fshared);
-       mutex_unlock(&lguest_lock);
-       return ret;
-}
-
-/*L:385 Note that our routines to access a different Guest's memory are called
- * lgread_other() and lgwrite_other(): these names emphasize that they are only
- * used when the Guest is *not* the current Guest.
- *
- * The interface for copying from another process's memory is called
- * access_process_vm(), with a final argument of 0 for a read, and 1 for a
- * write.
- *
- * We need lgread_other() to read the destination Guest's "struct lguest_dma"
- * array. */
-static int lgread_other(struct lguest *lg,
-                       void *buf, u32 addr, unsigned bytes)
-{
-       if (!lguest_address_ok(lg, addr, bytes)
-           || access_process_vm(lg->tsk, addr, buf, bytes, 0) != bytes) {
-               memset(buf, 0, bytes);
-               kill_guest(lg, "bad address in registered DMA struct");
-               return 0;
-       }
-       return 1;
-}
-
-/* "lgwrite()" to another Guest: used to update the destination "used_len" once
- * we've transferred data into the buffer. */
-static int lgwrite_other(struct lguest *lg, u32 addr,
-                        const void *buf, unsigned bytes)
-{
-       if (!lguest_address_ok(lg, addr, bytes)
-           || (access_process_vm(lg->tsk, addr, (void *)buf, bytes, 1)
-               != bytes)) {
-               kill_guest(lg, "bad address writing to registered DMA");
-               return 0;
-       }
-       return 1;
-}
-
-/*L:400 This is the generic engine which copies from a source "struct
- * lguest_dma" from this Guest into another Guest's "struct lguest_dma".  The
- * destination Guest's pages have already been mapped, as contained in the
- * pages array.
- *
- * If you're wondering if there's a nice "copy from one process to another"
- * routine, so was I.  But Linux isn't really set up to copy between two
- * unrelated processes, so we have to write it ourselves.
- */
-static u32 copy_data(struct lguest *srclg,
-                    const struct lguest_dma *src,
-                    const struct lguest_dma *dst,
-                    struct page *pages[])
-{
-       unsigned int totlen, si, di, srcoff, dstoff;
-       void *maddr = NULL;
-
-       /* We return the total length transferred. */
-       totlen = 0;
-
-       /* We keep indexes into the source and destination "struct lguest_dma",
-        * and an offset within each region. */
-       si = di = 0;
-       srcoff = dstoff = 0;
-
-       /* We loop until the source or destination is exhausted. */
-       while (si < LGUEST_MAX_DMA_SECTIONS && src->len[si]
-              && di < LGUEST_MAX_DMA_SECTIONS && dst->len[di]) {
-               /* We can only transfer the rest of the src buffer, or as much
-                * as will fit into the destination buffer. */
-               u32 len = min(src->len[si] - srcoff, dst->len[di] - dstoff);
-
-               /* For systems using "highmem" we need to use kmap() to access
-                * the page we want.  We often use the same page over and over,
-                * so rather than kmap() it on every loop, we set the maddr
-                * pointer to NULL when we need to move to the next
-                * destination page. */
-               if (!maddr)
-                       maddr = kmap(pages[di]);
-
-               /* Copy directly from (this Guest's) source address to the
-                * destination Guest's kmap()ed buffer.  Note that maddr points
-                * to the start of the page: we need to add the offset of the
-                * destination address and offset within the buffer. */
-
-               /* FIXME: This is not completely portable.  I looked at
-                * copy_to_user_page(), and some arch's seem to need special
-                * flushes.  x86 is fine. */
-               if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
-                                  (void __user *)src->addr[si], len) != 0) {
-                       /* If a copy failed, it's the source's fault. */
-                       kill_guest(srclg, "bad address in sending DMA");
-                       totlen = 0;
-                       break;
-               }
-
-               /* Increment the total and src & dst offsets */
-               totlen += len;
-               srcoff += len;
-               dstoff += len;
-
-               /* Presumably we reached the end of the src or dest buffers: */
-               if (srcoff == src->len[si]) {
-                       /* Move to the next buffer at offset 0 */
-                       si++;
-                       srcoff = 0;
-               }
-               if (dstoff == dst->len[di]) {
-                       /* We need to unmap that destination page and reset
-                        * maddr ready for the next one. */
-                       kunmap(pages[di]);
-                       maddr = NULL;
-                       di++;
-                       dstoff = 0;
-               }
-       }
-
-       /* If we still had a page mapped at the end, unmap now. */
-       if (maddr)
-               kunmap(pages[di]);
-
-       return totlen;
-}
-
-/*L:390 This is how we transfer a "struct lguest_dma" from the source Guest
- * (the current Guest which called SEND_DMA) to another Guest. */
-static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src,
-                 struct lguest *dstlg, const struct lguest_dma *dst)
-{
-       int i;
-       u32 ret;
-       struct page *pages[LGUEST_MAX_DMA_SECTIONS];
-
-       /* We check that both source and destination "struct lguest_dma"s are
-        * within the bounds of the source and destination Guests */
-       if (!check_dma_list(dstlg, dst) || !check_dma_list(srclg, src))
-               return 0;
-
-       /* We need to map the pages which correspond to each parts of
-        * destination buffer. */
-       for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
-               if (dst->len[i] == 0)
-                       break;
-               /* get_user_pages() is a complicated function, especially since
-                * we only want a single page.  But it works, and returns the
-                * number of pages.  Note that we're holding the destination's
-                * mmap_sem, as get_user_pages() requires. */
-               if (get_user_pages(dstlg->tsk, dstlg->mm,
-                                  dst->addr[i], 1, 1, 1, pages+i, NULL)
-                   != 1) {
-                       /* This means the destination gave us a bogus buffer */
-                       kill_guest(dstlg, "Error mapping DMA pages");
-                       ret = 0;
-                       goto drop_pages;
-               }
-       }
-
-       /* Now copy the data until we run out of src or dst. */
-       ret = copy_data(srclg, src, dst, pages);
-
-drop_pages:
-       while (--i >= 0)
-               put_page(pages[i]);
-       return ret;
-}
-
-/*L:380 Transferring data from one Guest to another is not as simple as I'd
- * like.  We've found the "struct lguest_dma_info" bound to the same address as
- * the send, we need to copy into it.
- *
- * This function returns true if the destination array was empty. */
-static int dma_transfer(struct lguest *srclg,
-                       unsigned long udma,
-                       struct lguest_dma_info *dst)
-{
-       struct lguest_dma dst_dma, src_dma;
-       struct lguest *dstlg;
-       u32 i, dma = 0;
-
-       /* From the "struct lguest_dma_info" we found in the hash, grab the
-        * Guest. */
-       dstlg = &lguests[dst->guestid];
-       /* Read in the source "struct lguest_dma" handed to SEND_DMA. */
-       lgread(srclg, &src_dma, udma, sizeof(src_dma));
-
-       /* We need the destination's mmap_sem, and we already hold the source's
-        * mmap_sem for the futex key lookup.  Normally this would suggest that
-        * we could deadlock if the destination Guest was trying to send to
-        * this source Guest at the same time, which is another reason that all
-        * I/O is done under the big lguest_lock. */
-       down_read(&dstlg->mm->mmap_sem);
-
-       /* Look through the destination DMA array for an available buffer. */
-       for (i = 0; i < dst->num_dmas; i++) {
-               /* We keep a "next_dma" pointer which often helps us avoid
-                * looking at lots of previously-filled entries. */
-               dma = (dst->next_dma + i) % dst->num_dmas;
-               if (!lgread_other(dstlg, &dst_dma,
-                                 dst->dmas + dma * sizeof(struct lguest_dma),
-                                 sizeof(dst_dma))) {
-                       goto fail;
-               }
-               if (!dst_dma.used_len)
-                       break;
-       }
-
-       /* If we found a buffer, we do the actual data copy. */
-       if (i != dst->num_dmas) {
-               unsigned long used_lenp;
-               unsigned int ret;
-
-               ret = do_dma(srclg, &src_dma, dstlg, &dst_dma);
-               /* Put used length in the source "struct lguest_dma"'s used_len
-                * field.  It's a little tricky to figure out where that is,
-                * though. */
-               lgwrite_u32(srclg,
-                           udma+offsetof(struct lguest_dma, used_len), ret);
-               /* Tranferring 0 bytes is OK if the source buffer was empty. */
-               if (ret == 0 && src_dma.len[0] != 0)
-                       goto fail;
-
-               /* The destination Guest might be running on a different CPU:
-                * we have to make sure that it will see the "used_len" field
-                * change to non-zero *after* it sees the data we copied into
-                * the buffer.  Hence a write memory barrier. */
-               wmb();
-               /* Figuring out where the destination's used_len field for this
-                * "struct lguest_dma" in the array is also a little ugly. */
-               used_lenp = dst->dmas
-                       + dma * sizeof(struct lguest_dma)
-                       + offsetof(struct lguest_dma, used_len);
-               lgwrite_other(dstlg, used_lenp, &ret, sizeof(ret));
-               /* Move the cursor for next time. */
-               dst->next_dma++;
-       }
-       up_read(&dstlg->mm->mmap_sem);
-
-       /* We trigger the destination interrupt, even if the destination was
-        * empty and we didn't transfer anything: this gives them a chance to
-        * wake up and refill. */
-       set_bit(dst->interrupt, dstlg->irqs_pending);
-       /* Wake up the destination process. */
-       wake_up_process(dstlg->tsk);
-       /* If we passed the last "struct lguest_dma", the receive had no
-        * buffers left. */
-       return i == dst->num_dmas;
-
-fail:
-       up_read(&dstlg->mm->mmap_sem);
-       return 0;
-}
-
-/*L:370 This is the counter-side to the BIND_DMA hypercall; the SEND_DMA
- * hypercall.  We find out who's listening, and send to them. */
-void send_dma(struct lguest *lg, unsigned long ukey, unsigned long udma)
-{
-       union futex_key key;
-       int empty = 0;
-       struct rw_semaphore *fshared = &current->mm->mmap_sem;
-
-again:
-       mutex_lock(&lguest_lock);
-       down_read(fshared);
-       /* Get the futex key for the key the Guest gave us */
-       if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
-               kill_guest(lg, "bad sending DMA key");
-               goto unlock;
-       }
-       /* Since the key must be a multiple of 4, the futex key uses the lower
-        * bit of the "offset" field (which would always be 0) to indicate a
-        * mapping which is shared with other processes (ie. Guests). */
-       if (key.shared.offset & 1) {
-               struct lguest_dma_info *i;
-               /* Look through the hash for other Guests. */
-               list_for_each_entry(i, &dma_hash[hash(&key)], list) {
-                       /* Don't send to ourselves. */
-                       if (i->guestid == lg->guestid)
-                               continue;
-                       if (!key_eq(&key, &i->key))
-                               continue;
-
-                       /* If dma_transfer() tells us the destination has no
-                        * available buffers, we increment "empty". */
-                       empty += dma_transfer(lg, udma, i);
-                       break;
-               }
-               /* If the destination is empty, we release our locks and
-                * give the destination Guest a brief chance to restock. */
-               if (empty == 1) {
-                       /* Give any recipients one chance to restock. */
-                       up_read(&current->mm->mmap_sem);
-                       mutex_unlock(&lguest_lock);
-                       /* Next time, we won't try again. */
-                       empty++;
-                       goto again;
-               }
-       } else {
-               /* Private mapping: Guest is sending to its Launcher.  We set
-                * the "dma_is_pending" flag so that the main loop will exit
-                * and the Launcher's read() from /dev/lguest will return. */
-               lg->dma_is_pending = 1;
-               lg->pending_dma = udma;
-               lg->pending_key = ukey;
-       }
-unlock:
-       up_read(fshared);
-       mutex_unlock(&lguest_lock);
-}
-/*:*/
-
-void release_all_dma(struct lguest *lg)
-{
-       unsigned int i;
-
-       BUG_ON(!mutex_is_locked(&lguest_lock));
-
-       down_read(&lg->mm->mmap_sem);
-       for (i = 0; i < LGUEST_MAX_DMA; i++) {
-               if (lg->dma[i].interrupt)
-                       unlink_dma(&lg->dma[i]);
-       }
-       up_read(&lg->mm->mmap_sem);
-}
-
-/*M:007 We only return a single DMA buffer to the Launcher, but it would be
- * more efficient to return a pointer to the entire array of DMA buffers, which
- * it can cache and choose one whenever it wants.
- *
- * Currently the Launcher uses a write to /dev/lguest, and the return value is
- * the address of the DMA structure with the interrupt number placed in
- * dma->used_len.  If we wanted to return the entire array, we need to return
- * the address, array size and interrupt number: this seems to require an
- * ioctl(). :*/
-
-/*L:320 This routine looks for a DMA buffer registered by the Guest on the
- * given key (using the BIND_DMA hypercall). */
-unsigned long get_dma_buffer(struct lguest *lg,
-                            unsigned long ukey, unsigned long *interrupt)
-{
-       unsigned long ret = 0;
-       union futex_key key;
-       struct lguest_dma_info *i;
-       struct rw_semaphore *fshared = &current->mm->mmap_sem;
-
-       /* Take the Big Lguest Lock to stop other Guests sending this Guest DMA
-        * at the same time. */
-       mutex_lock(&lguest_lock);
-       /* To match between Guests sharing the same underlying memory we steal
-        * code from the futex infrastructure.  This requires that we hold the
-        * "mmap_sem" for our process (the Launcher), and pass it to the futex
-        * code. */
-       down_read(fshared);
-
-       /* This can fail if it's not a valid address, or if the address is not
-        * divisible by 4 (the futex code needs that, we don't really). */
-       if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
-               kill_guest(lg, "bad registered DMA buffer");
-               goto unlock;
-       }
-       /* Search the hash table for matching entries (the Launcher can only
-        * send to its own Guest for the moment, so the entry must be for this
-        * Guest) */
-       list_for_each_entry(i, &dma_hash[hash(&key)], list) {
-               if (key_eq(&key, &i->key) && i->guestid == lg->guestid) {
-                       unsigned int j;
-                       /* Look through the registered DMA array for an
-                        * available buffer. */
-                       for (j = 0; j < i->num_dmas; j++) {
-                               struct lguest_dma dma;
-
-                               ret = i->dmas + j * sizeof(struct lguest_dma);
-                               lgread(lg, &dma, ret, sizeof(dma));
-                               if (dma.used_len == 0)
-                                       break;
-                       }
-                       /* Store the interrupt the Guest wants when the buffer
-                        * is used. */
-                       *interrupt = i->interrupt;
-                       break;
-               }
-       }
-unlock:
-       up_read(fshared);
-       mutex_unlock(&lguest_lock);
-       return ret;
-}
-/*:*/
-
-/*L:410 This really has completed the Launcher.  Not only have we now finished
- * the longest chapter in our journey, but this also means we are over halfway
- * through!
- *
- * Enough prevaricating around the bush: it is time for us to dive into the
- * core of the Host, in "make Host".
- */
index 64f0abe..d9144be 100644 (file)
 #ifndef _LGUEST_H
 #define _LGUEST_H
 
-#include <asm/desc.h>
-
-#define GDT_ENTRY_LGUEST_CS    10
-#define GDT_ENTRY_LGUEST_DS    11
-#define LGUEST_CS              (GDT_ENTRY_LGUEST_CS * 8)
-#define LGUEST_DS              (GDT_ENTRY_LGUEST_DS * 8)
-
 #ifndef __ASSEMBLY__
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/stringify.h>
-#include <linux/binfmts.h>
-#include <linux/futex.h>
 #include <linux/lguest.h>
 #include <linux/lguest_launcher.h>
 #include <linux/wait.h>
 #include <linux/err.h>
 #include <asm/semaphore.h>
-#include "irq_vectors.h"
-
-#define GUEST_PL 1
 
-struct lguest_regs
-{
-       /* Manually saved part. */
-       unsigned long ebx, ecx, edx;
-       unsigned long esi, edi, ebp;
-       unsigned long gs;
-       unsigned long eax;
-       unsigned long fs, ds, es;
-       unsigned long trapnum, errcode;
-       /* Trap pushed part */
-       unsigned long eip;
-       unsigned long cs;
-       unsigned long eflags;
-       unsigned long esp;
-       unsigned long ss;
-};
+#include <asm/lguest.h>
 
 void free_pagetables(void);
 int init_pagetables(struct page **switcher_page, unsigned int pages);
 
-/* Full 4G segment descriptors, suitable for CS and DS. */
-#define FULL_EXEC_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9b00})
-#define FULL_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9300})
-
-struct lguest_dma_info
-{
-       struct list_head list;
-       union futex_key key;
-       unsigned long dmas;
-       u16 next_dma;
-       u16 num_dmas;
-       u16 guestid;
-       u8 interrupt;   /* 0 when not registered */
-};
-
-/*H:310 The page-table code owes a great debt of gratitude to Andi Kleen.  He
- * reviewed the original code which used "u32" for all page table entries, and
- * insisted that it would be far clearer with explicit typing.  I thought it
- * was overkill, but he was right: it is much clearer than it was before.
- *
- * We have separate types for the Guest's ptes & pgds and the shadow ptes &
- * pgds.  There's already a Linux type for these (pte_t and pgd_t) but they
- * change depending on kernel config options (PAE). */
-
-/* Each entry is identical: lower 12 bits of flags and upper 20 bits for the
- * "page frame number" (0 == first physical page, etc).  They are different
- * types so the compiler will warn us if we mix them improperly. */
-typedef union {
-       struct { unsigned flags:12, pfn:20; };
-       struct { unsigned long val; } raw;
-} spgd_t;
-typedef union {
-       struct { unsigned flags:12, pfn:20; };
-       struct { unsigned long val; } raw;
-} spte_t;
-typedef union {
-       struct { unsigned flags:12, pfn:20; };
-       struct { unsigned long val; } raw;
-} gpgd_t;
-typedef union {
-       struct { unsigned flags:12, pfn:20; };
-       struct { unsigned long val; } raw;
-} gpte_t;
-
-/* We have two convenient macros to convert a "raw" value as handed to us by
- * the Guest into the correct Guest PGD or PTE type. */
-#define mkgpte(_val) ((gpte_t){.raw.val = _val})
-#define mkgpgd(_val) ((gpgd_t){.raw.val = _val})
-/*:*/
-
 struct pgdir
 {
-       unsigned long cr3;
-       spgd_t *pgdir;
-};
-
-/* This is a guest-specific page (mapped ro) into the guest. */
-struct lguest_ro_state
-{
-       /* Host information we need to restore when we switch back. */
-       u32 host_cr3;
-       struct Xgt_desc_struct host_idt_desc;
-       struct Xgt_desc_struct host_gdt_desc;
-       u32 host_sp;
-
-       /* Fields which are used when guest is running. */
-       struct Xgt_desc_struct guest_idt_desc;
-       struct Xgt_desc_struct guest_gdt_desc;
-       struct i386_hw_tss guest_tss;
-       struct desc_struct guest_idt[IDT_ENTRIES];
-       struct desc_struct guest_gdt[GDT_ENTRIES];
+       unsigned long gpgdir;
+       pgd_t *pgdir;
 };
 
 /* We have two pages shared with guests, per cpu.  */
@@ -141,9 +47,11 @@ struct lguest
        struct lguest_data __user *lguest_data;
        struct task_struct *tsk;
        struct mm_struct *mm;   /* == tsk->mm, but that becomes NULL on exit */
-       u16 guestid;
        u32 pfn_limit;
-       u32 page_offset;
+       /* This provides the offset to the base of guest-physical
+        * memory in the Launcher. */
+       void __user *mem_base;
+       unsigned long kernel_address;
        u32 cr2;
        int halted;
        int ts;
@@ -151,6 +59,9 @@ struct lguest
        u32 esp1;
        u8 ss1;
 
+       /* If a hypercall was asked for, this points to the arguments. */
+       struct hcall_args *hcall;
+
        /* Do we need to stop what we're doing and return to userspace? */
        int break_out;
        wait_queue_head_t break_wq;
@@ -167,24 +78,15 @@ struct lguest
        struct task_struct *wake;
 
        unsigned long noirq_start, noirq_end;
-       int dma_is_pending;
-       unsigned long pending_dma; /* struct lguest_dma */
-       unsigned long pending_key; /* address they're sending to */
+       unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */
 
        unsigned int stack_pages;
        u32 tsc_khz;
 
-       struct lguest_dma_info dma[LGUEST_MAX_DMA];
-
        /* Dead? */
        const char *dead;
 
-       /* The GDT entries copied into lguest_ro_state when running. */
-       struct desc_struct gdt[GDT_ENTRIES];
-
-       /* The IDT entries: some copied into lguest_ro_state when running. */
-       struct desc_struct idt[FIRST_EXTERNAL_VECTOR+LGUEST_IRQS];
-       struct desc_struct syscall_idt;
+       struct lguest_arch arch;
 
        /* Virtual clock device */
        struct hrtimer hrt;
@@ -193,19 +95,38 @@ struct lguest
        DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
 };
 
-extern struct lguest lguests[];
 extern struct mutex lguest_lock;
 
 /* core.c: */
-u32 lgread_u32(struct lguest *lg, unsigned long addr);
-void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val);
-void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len);
-void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len);
-int find_free_guest(void);
 int lguest_address_ok(const struct lguest *lg,
                      unsigned long addr, unsigned long len);
+void __lgread(struct lguest *, void *, unsigned long, unsigned);
+void __lgwrite(struct lguest *, unsigned long, const void *, unsigned);
+
+/*L:306 Using memory-copy operations like that is usually inconvient, so we
+ * have the following helper macros which read and write a specific type (often
+ * an unsigned long).
+ *
+ * This reads into a variable of the given type then returns that. */
+#define lgread(lg, addr, type)                                         \
+       ({ type _v; __lgread((lg), &_v, (addr), sizeof(_v)); _v; })
+
+/* This checks that the variable is of the given type, then writes it out. */
+#define lgwrite(lg, addr, type, val)                           \
+       do {                                                    \
+               typecheck(type, val);                           \
+               __lgwrite((lg), (addr), &(val), sizeof(val));   \
+       } while(0)
+/* (end of memory access helper routines) :*/
+
 int run_guest(struct lguest *lg, unsigned long __user *user);
 
+/* Helper macros to obtain the first 12 or the last 20 bits, this is only the
+ * first step in the migration to the kernel types.  pte_pfn is already defined
+ * in the kernel. */
+#define pgd_flags(x)   (pgd_val(x) & ~PAGE_MASK)
+#define pte_flags(x)   (pte_val(x) & ~PAGE_MASK)
+#define pgd_pfn(x)     (pgd_val(x) >> PAGE_SHIFT)
 
 /* interrupts_and_traps.c: */
 void maybe_do_interrupt(struct lguest *lg);
@@ -219,6 +140,9 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt,
                const unsigned long *def);
 void guest_set_clockevent(struct lguest *lg, unsigned long delta);
 void init_clockdev(struct lguest *lg);
+bool check_syscall_vector(struct lguest *lg);
+int init_interrupts(void);
+void free_interrupts(void);
 
 /* segments.c: */
 void setup_default_gdt_entries(struct lguest_ro_state *state);
@@ -232,28 +156,33 @@ void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt);
 int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
 void free_guest_pagetable(struct lguest *lg);
 void guest_new_pagetable(struct lguest *lg, unsigned long pgtable);
-void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 i);
+void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i);
 void guest_pagetable_clear_all(struct lguest *lg);
 void guest_pagetable_flush_user(struct lguest *lg);
-void guest_set_pte(struct lguest *lg, unsigned long cr3,
-                  unsigned long vaddr, gpte_t val);
+void guest_set_pte(struct lguest *lg, unsigned long gpgdir,
+                  unsigned long vaddr, pte_t val);
 void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages);
 int demand_page(struct lguest *info, unsigned long cr2, int errcode);
 void pin_page(struct lguest *lg, unsigned long vaddr);
+unsigned long guest_pa(struct lguest *lg, unsigned long vaddr);
+void page_table_guest_data_init(struct lguest *lg);
+
+/* <arch>/core.c: */
+void lguest_arch_host_init(void);
+void lguest_arch_host_fini(void);
+void lguest_arch_run_guest(struct lguest *lg);
+void lguest_arch_handle_trap(struct lguest *lg);
+int lguest_arch_init_hypercalls(struct lguest *lg);
+int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args);
+void lguest_arch_setup_regs(struct lguest *lg, unsigned long start);
+
+/* <arch>/switcher.S: */
+extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
 
 /* lguest_user.c: */
 int lguest_device_init(void);
 void lguest_device_remove(void);
 
-/* io.c: */
-void lguest_io_init(void);
-int bind_dma(struct lguest *lg,
-            unsigned long key, unsigned long udma, u16 numdmas, u8 interrupt);
-void send_dma(struct lguest *info, unsigned long key, unsigned long udma);
-void release_all_dma(struct lguest *lg);
-unsigned long get_dma_buffer(struct lguest *lg, unsigned long key,
-                            unsigned long *interrupt);
-
 /* hypercalls.c: */
 void do_hypercalls(struct lguest *lg);
 void write_timestamp(struct lguest *lg);
@@ -292,9 +221,5 @@ do {                                                                \
 } while(0)
 /* (End of aside) :*/
 
-static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
-{
-       return vaddr - lg->page_offset;
-}
 #endif /* __ASSEMBLY__ */
 #endif /* _LGUEST_H */
diff --git a/drivers/lguest/lguest_bus.c b/drivers/lguest/lguest_bus.c
deleted file mode 100644 (file)
index 5732978..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/*P:050 Lguest guests use a very simple bus for devices.  It's a simple array
- * of device descriptors contained just above the top of normal memory.  The
- * lguest bus is 80% tedious boilerplate code. :*/
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/lguest_bus.h>
-#include <asm/io.h>
-#include <asm/paravirt.h>
-
-static ssize_t type_show(struct device *_dev,
-                         struct device_attribute *attr, char *buf)
-{
-       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
-       return sprintf(buf, "%hu", lguest_devices[dev->index].type);
-}
-static ssize_t features_show(struct device *_dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
-       return sprintf(buf, "%hx", lguest_devices[dev->index].features);
-}
-static ssize_t pfn_show(struct device *_dev,
-                        struct device_attribute *attr, char *buf)
-{
-       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
-       return sprintf(buf, "%u", lguest_devices[dev->index].pfn);
-}
-static ssize_t status_show(struct device *_dev,
-                           struct device_attribute *attr, char *buf)
-{
-       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
-       return sprintf(buf, "%hx", lguest_devices[dev->index].status);
-}
-static ssize_t status_store(struct device *_dev, struct device_attribute *attr,
-                            const char *buf, size_t count)
-{
-       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
-       if (sscanf(buf, "%hi", &lguest_devices[dev->index].status) != 1)
-               return -EINVAL;
-       return count;
-}
-static struct device_attribute lguest_dev_attrs[] = {
-       __ATTR_RO(type),
-       __ATTR_RO(features),
-       __ATTR_RO(pfn),
-       __ATTR(status, 0644, status_show, status_store),
-       __ATTR_NULL
-};
-
-/*D:130 The generic bus infrastructure requires a function which says whether a
- * device matches a driver.  For us, it is simple: "struct lguest_driver"
- * contains a "device_type" field which indicates what type of device it can
- * handle, so we just cast the args and compare: */
-static int lguest_dev_match(struct device *_dev, struct device_driver *_drv)
-{
-       struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
-       struct lguest_driver *drv = container_of(_drv,struct lguest_driver,drv);
-
-       return (drv->device_type == lguest_devices[dev->index].type);
-}
-/*:*/
-
-struct lguest_bus {
-       struct bus_type bus;
-       struct device dev;
-};
-
-static struct lguest_bus lguest_bus = {
-       .bus = {
-               .name  = "lguest",
-               .match = lguest_dev_match,
-               .dev_attrs = lguest_dev_attrs,
-       },
-       .dev = {
-               .parent = NULL,
-               .bus_id = "lguest",
-       }
-};
-
-/*D:140 This is the callback which occurs once the bus infrastructure matches
- * up a device and driver, ie. in response to add_lguest_device() calling
- * device_register(), or register_lguest_driver() calling driver_register().
- *
- * At the moment it's always the latter: the devices are added first, since
- * scan_devices() is called from a "core_initcall", and the drivers themselves
- * called later as a normal "initcall".  But it would work the other way too.
- *
- * So now we have the happy couple, we add the status bit to indicate that we
- * found a driver.  If the driver truly loves the device, it will return
- * happiness from its probe function (ok, perhaps this wasn't my greatest
- * analogy), and we set the final "driver ok" bit so the Host sees it's all
- * green. */
-static int lguest_dev_probe(struct device *_dev)
-{
-       int ret;
-       struct lguest_device*dev = container_of(_dev,struct lguest_device,dev);
-       struct lguest_driver*drv = container_of(dev->dev.driver,
-                                               struct lguest_driver, drv);
-
-       lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER;
-       ret = drv->probe(dev);
-       if (ret == 0)
-               lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER_OK;
-       return ret;
-}
-
-/* The last part of the bus infrastructure is the function lguest drivers use
- * to register themselves.  Firstly, we do nothing if there's no lguest bus
- * (ie. this is not a Guest), otherwise we fill in the embedded generic "struct
- * driver" fields and call the generic driver_register(). */
-int register_lguest_driver(struct lguest_driver *drv)
-{
-       if (!lguest_devices)
-               return 0;
-
-       drv->drv.bus = &lguest_bus.bus;
-       drv->drv.name = drv->name;
-       drv->drv.owner = drv->owner;
-       drv->drv.probe = lguest_dev_probe;
-
-       return driver_register(&drv->drv);
-}
-
-/* At the moment we build all the drivers into the kernel because they're so
- * simple: 8144 bytes for all three of them as I type this.  And as the console
- * really needs to be built in, it's actually only 3527 bytes for the network
- * and block drivers.
- *
- * If they get complex it will make sense for them to be modularized, so we
- * need to explicitly export the symbol.
- *
- * I don't think non-GPL modules make sense, so it's a GPL-only export.
- */
-EXPORT_SYMBOL_GPL(register_lguest_driver);
-
-/*D:120 This is the core of the lguest bus: actually adding a new device.
- * It's a separate function because it's neater that way, and because an
- * earlier version of the code supported hotplug and unplug.  They were removed
- * early on because they were never used.
- *
- * As Andrew Tridgell says, "Untested code is buggy code".
- *
- * It's worth reading this carefully: we start with an index into the array of
- * "struct lguest_device_desc"s indicating the device which is new: */
-static void add_lguest_device(unsigned int index)
-{
-       struct lguest_device *new;
-
-       /* Each "struct lguest_device_desc" has a "status" field, which the
-        * Guest updates as the device is probed.  In the worst case, the Host
-        * can look at these bits to tell what part of device setup failed,
-        * even if the console isn't available. */
-       lguest_devices[index].status |= LGUEST_DEVICE_S_ACKNOWLEDGE;
-       new = kmalloc(sizeof(struct lguest_device), GFP_KERNEL);
-       if (!new) {
-               printk(KERN_EMERG "Cannot allocate lguest device %u\n", index);
-               lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
-               return;
-       }
-
-       /* The "struct lguest_device" setup is pretty straight-forward example
-        * code. */
-       new->index = index;
-       new->private = NULL;
-       memset(&new->dev, 0, sizeof(new->dev));
-       new->dev.parent = &lguest_bus.dev;
-       new->dev.bus = &lguest_bus.bus;
-       sprintf(new->dev.bus_id, "%u", index);
-
-       /* device_register() causes the bus infrastructure to look for a
-        * matching driver. */
-       if (device_register(&new->dev) != 0) {
-               printk(KERN_EMERG "Cannot register lguest device %u\n", index);
-               lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
-               kfree(new);
-       }
-}
-
-/*D:110 scan_devices() simply iterates through the device array.  The type 0
- * is reserved to mean "no device", and anything else means we have found a
- * device: add it. */
-static void scan_devices(void)
-{
-       unsigned int i;
-
-       for (i = 0; i < LGUEST_MAX_DEVICES; i++)
-               if (lguest_devices[i].type)
-                       add_lguest_device(i);
-}
-
-/*D:100 Fairly early in boot, lguest_bus_init() is called to set up the lguest
- * bus.  We check that we are a Guest by checking paravirt_ops.name: there are
- * other ways of checking, but this seems most obvious to me.
- *
- * So we can access the array of "struct lguest_device_desc"s easily, we map
- * that memory and store the pointer in the global "lguest_devices".  Then we
- * register the bus with the core.  Doing two registrations seems clunky to me,
- * but it seems to be the correct sysfs incantation.
- *
- * Finally we call scan_devices() which adds all the devices found in the
- * "struct lguest_device_desc" array. */
-static int __init lguest_bus_init(void)
-{
-       if (strcmp(pv_info.name, "lguest") != 0)
-               return 0;
-
-       /* Devices are in a single page above top of "normal" mem */
-       lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
-
-       if (bus_register(&lguest_bus.bus) != 0
-           || device_register(&lguest_bus.dev) != 0)
-               panic("lguest bus registration failed");
-
-       scan_devices();
-       return 0;
-}
-/* Do this after core stuff, before devices. */
-postcore_initcall(lguest_bus_init);
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
new file mode 100644 (file)
index 0000000..71c6483
--- /dev/null
@@ -0,0 +1,373 @@
+/*P:050 Lguest guests use a very simple method to describe devices.  It's a
+ * series of device descriptors contained just above the top of normal
+ * memory.
+ *
+ * We use the standard "virtio" device infrastructure, which provides us with a
+ * console, a network and a block driver.  Each one expects some configuration
+ * information and a "virtqueue" mechanism to send and receive data. :*/
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/lguest_launcher.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/interrupt.h>
+#include <linux/virtio_ring.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/paravirt.h>
+#include <asm/lguest_hcall.h>
+
+/* The pointer to our (page) of device descriptions. */
+static void *lguest_devices;
+
+/* Unique numbering for lguest devices. */
+static unsigned int dev_index;
+
+/* For Guests, device memory can be used as normal memory, so we cast away the
+ * __iomem to quieten sparse. */
+static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
+{
+       return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
+}
+
+static inline void lguest_unmap(void *addr)
+{
+       iounmap((__force void __iomem *)addr);
+}
+
+/*D:100 Each lguest device is just a virtio device plus a pointer to its entry
+ * in the lguest_devices page. */
+struct lguest_device {
+       struct virtio_device vdev;
+
+       /* The entry in the lguest_devices page for this device. */
+       struct lguest_device_desc *desc;
+};
+
+/* Since the virtio infrastructure hands us a pointer to the virtio_device all
+ * the time, it helps to have a curt macro to get a pointer to the struct
+ * lguest_device it's enclosed in.  */
+#define to_lgdev(vdev) container_of(vdev, struct lguest_device, vdev)
+
+/*D:130
+ * Device configurations
+ *
+ * The configuration information for a device consists of a series of fields.
+ * The device will look for these fields during setup.
+ *
+ * For us these fields come immediately after that device's descriptor in the
+ * lguest_devices page.
+ *
+ * Each field starts with a "type" byte, a "length" byte, then that number of
+ * bytes of configuration information.  The device descriptor tells us the
+ * total configuration length so we know when we've reached the last field. */
+
+/* type + length bytes */
+#define FHDR_LEN 2
+
+/* This finds the first field of a given type for a device's configuration. */
+static void *lg_find(struct virtio_device *vdev, u8 type, unsigned int *len)
+{
+       struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+       int i;
+
+       for (i = 0; i < desc->config_len; i += FHDR_LEN + desc->config[i+1]) {
+               if (desc->config[i] == type) {
+                       /* Mark it used, so Host can know we looked at it, and
+                        * also so we won't find the same one twice. */
+                       desc->config[i] |= 0x80;
+                       /* Remember, the second byte is the length. */
+                       *len = desc->config[i+1];
+                       /* We return a pointer to the field header. */
+                       return desc->config + i;
+               }
+       }
+
+       /* Not found: return NULL for failure. */
+       return NULL;
+}
+
+/* Once they've found a field, getting a copy of it is easy. */
+static void lg_get(struct virtio_device *vdev, void *token,
+                  void *buf, unsigned len)
+{
+       /* Check they didn't ask for more than the length of the field! */
+       BUG_ON(len > ((u8 *)token)[1]);
+       memcpy(buf, token + FHDR_LEN, len);
+}
+
+/* Setting the contents is also trivial. */
+static void lg_set(struct virtio_device *vdev, void *token,
+                  const void *buf, unsigned len)
+{
+       BUG_ON(len > ((u8 *)token)[1]);
+       memcpy(token + FHDR_LEN, buf, len);
+}
+
+/* The operations to get and set the status word just access the status field
+ * of the device descriptor. */
+static u8 lg_get_status(struct virtio_device *vdev)
+{
+       return to_lgdev(vdev)->desc->status;
+}
+
+static void lg_set_status(struct virtio_device *vdev, u8 status)
+{
+       to_lgdev(vdev)->desc->status = status;
+}
+
+/*
+ * Virtqueues
+ *
+ * The other piece of infrastructure virtio needs is a "virtqueue": a way of
+ * the Guest device registering buffers for the other side to read from or
+ * write into (ie. send and receive buffers).  Each device can have multiple
+ * virtqueues: for example the console has one queue for sending and one for
+ * receiving.
+ *
+ * Fortunately for us, a very fast shared-memory-plus-descriptors virtqueue
+ * already exists in virtio_ring.c.  We just need to connect it up.
+ *
+ * We start with the information we need to keep about each virtqueue.
+ */
+
+/*D:140 This is the information we remember about each virtqueue. */
+struct lguest_vq_info
+{
+       /* A copy of the information contained in the device config. */
+       struct lguest_vqconfig config;
+
+       /* The address where we mapped the virtio ring, so we can unmap it. */
+       void *pages;
+};
+
+/* When the virtio_ring code wants to prod the Host, it calls us here and we
+ * make a hypercall.  We hand the page number of the virtqueue so the Host
+ * knows which virtqueue we're talking about. */
+static void lg_notify(struct virtqueue *vq)
+{
+       /* We store our virtqueue information in the "priv" pointer of the
+        * virtqueue structure. */
+       struct lguest_vq_info *lvq = vq->priv;
+
+       hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0);
+}
+
+/* This routine finds the first virtqueue described in the configuration of
+ * this device and sets it up.
+ *
+ * This is kind of an ugly duckling.  It'd be nicer to have a standard
+ * representation of a virtqueue in the configuration space, but it seems that
+ * everyone wants to do it differently.  The KVM guys want the Guest to
+ * allocate its own pages and tell the Host where they are, but for lguest it's
+ * simpler for the Host to simply tell us where the pages are.
+ *
+ * So we provide devices with a "find virtqueue and set it up" function. */
+static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
+                                   bool (*callback)(struct virtqueue *vq))
+{
+       struct lguest_vq_info *lvq;
+       struct virtqueue *vq;
+       unsigned int len;
+       void *token;
+       int err;
+
+       /* Look for a field of the correct type to mark a virtqueue.  Note that
+        * if this succeeds, then the type will be changed so it won't be found
+        * again, and future lg_find_vq() calls will find the next
+        * virtqueue (if any). */
+       token = vdev->config->find(vdev, VIRTIO_CONFIG_F_VIRTQUEUE, &len);
+       if (!token)
+               return ERR_PTR(-ENOENT);
+
+       lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
+       if (!lvq)
+               return ERR_PTR(-ENOMEM);
+
+       /* Note: we could use a configuration space inside here, just like we
+        * do for the device.  This would allow expansion in future, because
+        * our configuration system is designed to be expansible.  But this is
+        * way easier. */
+       if (len != sizeof(lvq->config)) {
+               dev_err(&vdev->dev, "Unexpected virtio config len %u\n", len);
+               err = -EIO;
+               goto free_lvq;
+       }
+       /* Make a copy of the "struct lguest_vqconfig" field.  We need a copy
+        * because the config space might not be aligned correctly. */
+       vdev->config->get(vdev, token, &lvq->config, sizeof(lvq->config));
+
+       /* Figure out how many pages the ring will take, and map that memory */
+       lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
+                               DIV_ROUND_UP(vring_size(lvq->config.num),
+                                            PAGE_SIZE));
+       if (!lvq->pages) {
+               err = -ENOMEM;
+               goto free_lvq;
+       }
+
+       /* OK, tell virtio_ring.c to set up a virtqueue now we know its size
+        * and we've got a pointer to its pages. */
+       vq = vring_new_virtqueue(lvq->config.num, vdev, lvq->pages,
+                                lg_notify, callback);
+       if (!vq) {
+               err = -ENOMEM;
+               goto unmap;
+       }
+
+       /* Tell the interrupt for this virtqueue to go to the virtio_ring
+        * interrupt handler. */
+       /* FIXME: We used to have a flag for the Host to tell us we could use
+        * the interrupt as a source of randomness: it'd be nice to have that
+        * back.. */
+       err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
+                         vdev->dev.bus_id, vq);
+       if (err)
+               goto destroy_vring;
+
+       /* Last of all we hook up our 'struct lguest_vq_info" to the
+        * virtqueue's priv pointer. */
+       vq->priv = lvq;
+       return vq;
+
+destroy_vring:
+       vring_del_virtqueue(vq);
+unmap:
+       lguest_unmap(lvq->pages);
+free_lvq:
+       kfree(lvq);
+       return ERR_PTR(err);
+}
+/*:*/
+
+/* Cleaning up a virtqueue is easy */
+static void lg_del_vq(struct virtqueue *vq)
+{
+       struct lguest_vq_info *lvq = vq->priv;
+
+       /* Tell virtio_ring.c to free the virtqueue. */
+       vring_del_virtqueue(vq);
+       /* Unmap the pages containing the ring. */
+       lguest_unmap(lvq->pages);
+       /* Free our own queue information. */
+       kfree(lvq);
+}
+
+/* The ops structure which hooks everything together. */
+static struct virtio_config_ops lguest_config_ops = {
+       .find = lg_find,
+       .get = lg_get,
+       .set = lg_set,
+       .get_status = lg_get_status,
+       .set_status = lg_set_status,
+       .find_vq = lg_find_vq,
+       .del_vq = lg_del_vq,
+};
+
+/* The root device for the lguest virtio devices.  This makes them appear as
+ * /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2. */
+static struct device lguest_root = {
+       .parent = NULL,
+       .bus_id = "lguest",
+};
+
+/*D:120 This is the core of the lguest bus: actually adding a new device.
+ * It's a separate function because it's neater that way, and because an
+ * earlier version of the code supported hotplug and unplug.  They were removed
+ * early on because they were never used.
+ *
+ * As Andrew Tridgell says, "Untested code is buggy code".
+ *
+ * It's worth reading this carefully: we start with a pointer to the new device
+ * descriptor in the "lguest_devices" page. */
+static void add_lguest_device(struct lguest_device_desc *d)
+{
+       struct lguest_device *ldev;
+
+       ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
+       if (!ldev) {
+               printk(KERN_EMERG "Cannot allocate lguest dev %u\n",
+                      dev_index++);
+               return;
+       }
+
+       /* This devices' parent is the lguest/ dir. */
+       ldev->vdev.dev.parent = &lguest_root;
+       /* We have a unique device index thanks to the dev_index counter. */
+       ldev->vdev.index = dev_index++;
+       /* The device type comes straight from the descriptor.  There's also a
+        * device vendor field in the virtio_device struct, which we leave as
+        * 0. */
+       ldev->vdev.id.device = d->type;
+       /* We have a simple set of routines for querying the device's
+        * configuration information and setting its status. */
+       ldev->vdev.config = &lguest_config_ops;
+       /* And we remember the device's descriptor for lguest_config_ops. */
+       ldev->desc = d;
+
+       /* register_virtio_device() sets up the generic fields for the struct
+        * virtio_device and calls device_register().  This makes the bus
+        * infrastructure look for a matching driver. */
+       if (register_virtio_device(&ldev->vdev) != 0) {
+               printk(KERN_ERR "Failed to register lguest device %u\n",
+                      ldev->vdev.index);
+               kfree(ldev);
+       }
+}
+
+/*D:110 scan_devices() simply iterates through the device page.  The type 0 is
+ * reserved to mean "end of devices". */
+static void scan_devices(void)
+{
+       unsigned int i;
+       struct lguest_device_desc *d;
+
+       /* We start at the page beginning, and skip over each entry. */
+       for (i = 0; i < PAGE_SIZE; i += sizeof(*d) + d->config_len) {
+               d = lguest_devices + i;
+
+               /* Once we hit a zero, stop. */
+               if (d->type == 0)
+                       break;
+
+               add_lguest_device(d);
+       }
+}
+
+/*D:105 Fairly early in boot, lguest_devices_init() is called to set up the
+ * lguest device infrastructure.  We check that we are a Guest by checking
+ * pv_info.name: there are other ways of checking, but this seems most
+ * obvious to me.
+ *
+ * So we can access the "struct lguest_device_desc"s easily, we map that memory
+ * and store the pointer in the global "lguest_devices".  Then we register a
+ * root device from which all our devices will hang (this seems to be the
+ * correct sysfs incantation).
+ *
+ * Finally we call scan_devices() which adds all the devices found in the
+ * lguest_devices page. */
+static int __init lguest_devices_init(void)
+{
+       if (strcmp(pv_info.name, "lguest") != 0)
+               return 0;
+
+       if (device_register(&lguest_root) != 0)
+               panic("Could not register lguest root");
+
+       /* Devices are in a single page above top of "normal" mem */
+       lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
+
+       scan_devices();
+       return 0;
+}
+/* We do this after core stuff, but before the drivers. */
+postcore_initcall(lguest_devices_init);
+
+/*D:150 At this point in the journey we used to now wade through the lguest
+ * devices themselves: net, block and console.  Since they're all now virtio
+ * devices rather than lguest-specific, I've decided to ignore them.  Mostly,
+ * they're kind of boring.  But this does mean you'll never experience the
+ * thrill of reading the forbidden love scene buried deep in the block driver.
+ *
+ * "make Launcher" beckons, where we answer questions like "Where do Guests
+ * come from?", and "What do you do when someone asks for optimization?". */
index 80d1b58..ee405b3 100644 (file)
@@ -1,73 +1,17 @@
 /*P:200 This contains all the /dev/lguest code, whereby the userspace launcher
  * controls and communicates with the Guest.  For example, the first write will
- * tell us the memory size, pagetable, entry point and kernel address offset.
- * A read will run the Guest until a signal is pending (-EINTR), or the Guest
- * does a DMA out to the Launcher.  Writes are also used to get a DMA buffer
- * registered by the Guest and to send the Guest an interrupt. :*/
+ * tell us the Guest's memory layout, pagetable, entry point and kernel address
+ * offset.  A read will run the Guest until something happens, such as a signal
+ * or the Guest doing a NOTIFY out to the Launcher. :*/
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
 #include "lg.h"
 
-/*L:030 setup_regs() doesn't really belong in this file, but it gives us an
- * early glimpse deeper into the Host so it's worth having here.
- *
- * Most of the Guest's registers are left alone: we used get_zeroed_page() to
- * allocate the structure, so they will be 0. */
-static void setup_regs(struct lguest_regs *regs, unsigned long start)
-{
-       /* There are four "segment" registers which the Guest needs to boot:
-        * The "code segment" register (cs) refers to the kernel code segment
-        * __KERNEL_CS, and the "data", "extra" and "stack" segment registers
-        * refer to the kernel data segment __KERNEL_DS.
-        *
-        * The privilege level is packed into the lower bits.  The Guest runs
-        * at privilege level 1 (GUEST_PL).*/
-       regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
-       regs->cs = __KERNEL_CS|GUEST_PL;
-
-       /* The "eflags" register contains miscellaneous flags.  Bit 1 (0x002)
-        * is supposed to always be "1".  Bit 9 (0x200) controls whether
-        * interrupts are enabled.  We always leave interrupts enabled while
-        * running the Guest. */
-       regs->eflags = 0x202;
-
-       /* The "Extended Instruction Pointer" register says where the Guest is
-        * running. */
-       regs->eip = start;
-
-       /* %esi points to our boot information, at physical address 0, so don't
-        * touch it. */
-}
-
-/*L:310 To send DMA into the Guest, the Launcher needs to be able to ask for a
- * DMA buffer.  This is done by writing LHREQ_GETDMA and the key to
- * /dev/lguest. */
-static long user_get_dma(struct lguest *lg, const u32 __user *input)
-{
-       unsigned long key, udma, irq;
-
-       /* Fetch the key they wrote to us. */
-       if (get_user(key, input) != 0)
-               return -EFAULT;
-       /* Look for a free Guest DMA buffer bound to that key. */
-       udma = get_dma_buffer(lg, key, &irq);
-       if (!udma)
-               return -ENOENT;
-
-       /* We need to tell the Launcher what interrupt the Guest expects after
-        * the buffer is filled.  We stash it in udma->used_len. */
-       lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq);
-
-       /* The (guest-physical) address of the DMA buffer is returned from
-        * the write(). */
-       return udma;
-}
-
 /*L:315 To force the Guest to stop running and return to the Launcher, the
  * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest.  The
  * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
-static int break_guest_out(struct lguest *lg, const u32 __user *input)
+static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
 {
        unsigned long on;
 
@@ -90,9 +34,9 @@ static int break_guest_out(struct lguest *lg, const u32 __user *input)
 
 /*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
  * number to /dev/lguest. */
-static int user_send_irq(struct lguest *lg, const u32 __user *input)
+static int user_send_irq(struct lguest *lg, const unsigned long __user *input)
 {
-       u32 irq;
+       unsigned long irq;
 
        if (get_user(irq, input) != 0)
                return -EFAULT;
@@ -133,17 +77,19 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
                return len;
        }
 
-       /* If we returned from read() last time because the Guest sent DMA,
+       /* If we returned from read() last time because the Guest notified,
         * clear the flag. */
-       if (lg->dma_is_pending)
-               lg->dma_is_pending = 0;
+       if (lg->pending_notify)
+               lg->pending_notify = 0;
 
        /* Run the Guest until something interesting happens. */
        return run_guest(lg, (unsigned long __user *)user);
 }
 
-/*L:020 The initialization write supplies 4 32-bit values (in addition to the
- * 32-bit LHREQ_INITIALIZE value).  These are:
+/*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit)
+ * values (in addition to the LHREQ_INITIALIZE value).  These are:
+ *
+ * base: The start of the Guest-physical memory inside the Launcher memory.
  *
  * pfnlimit: The highest (Guest-physical) page number the Guest should be
  * allowed to access.  The Launcher has to live in Guest memory, so it sets
@@ -153,23 +99,17 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
  * pagetables (which are set up by the Launcher).
  *
  * start: The first instruction to execute ("eip" in x86-speak).
- *
- * page_offset: The PAGE_OFFSET constant in the Guest kernel.  We should
- * probably wean the code off this, but it's a very useful constant!  Any
- * address above this is within the Guest kernel, and any kernel address can
- * quickly converted from physical to virtual by adding PAGE_OFFSET.  It's
- * 0xC0000000 (3G) by default, but it's configurable at kernel build time.
  */
-static int initialize(struct file *file, const u32 __user *input)
+static int initialize(struct file *file, const unsigned long __user *input)
 {
        /* "struct lguest" contains everything we (the Host) know about a
         * Guest. */
        struct lguest *lg;
-       int err, i;
-       u32 args[4];
+       int err;
+       unsigned long args[4];
 
-       /* We grab the Big Lguest lock, which protects the global array
-        * "lguests" and multiple simultaneous initializations. */
+       /* We grab the Big Lguest lock, which protects against multiple
+        * simultaneous initializations. */
        mutex_lock(&lguest_lock);
        /* You can't initialize twice!  Close the device and start again... */
        if (file->private_data) {
@@ -182,20 +122,15 @@ static int initialize(struct file *file, const u32 __user *input)
                goto unlock;
        }
 
-       /* Find an unused guest. */
-       i = find_free_guest();
-       if (i < 0) {
-               err = -ENOSPC;
+       lg = kzalloc(sizeof(*lg), GFP_KERNEL);
+       if (!lg) {
+               err = -ENOMEM;
                goto unlock;
        }
-       /* OK, we have an index into the "lguest" array: "lg" is a convenient
-        * pointer. */
-       lg = &lguests[i];
 
        /* Populate the easy fields of our "struct lguest" */
-       lg->guestid = i;
-       lg->pfn_limit = args[0];
-       lg->page_offset = args[3];
+       lg->mem_base = (void __user *)(long)args[0];
+       lg->pfn_limit = args[1];
 
        /* We need a complete page for the Guest registers: they are accessible
         * to the Guest and we can only grant it access to whole pages. */
@@ -210,17 +145,13 @@ static int initialize(struct file *file, const u32 __user *input)
        /* Initialize the Guest's shadow page tables, using the toplevel
         * address the Launcher gave us.  This allocates memory, so can
         * fail. */
-       err = init_guest_pagetable(lg, args[1]);
+       err = init_guest_pagetable(lg, args[2]);
        if (err)
                goto free_regs;
 
        /* Now we initialize the Guest's registers, handing it the start
         * address. */
-       setup_regs(lg->regs, args[2]);
-
-       /* There are a couple of GDT entries the Guest expects when first
-        * booting. */
-       setup_guest_gdt(lg);
+       lguest_arch_setup_regs(lg, args[3]);
 
        /* The timer for lguest's clock needs initialization. */
        init_clockdev(lg);
@@ -260,18 +191,19 @@ unlock:
 /*L:010 The first operation the Launcher does must be a write.  All writes
  * start with a 32 bit number: for the first write this must be
  * LHREQ_INITIALIZE to set up the Guest.  After that the Launcher can use
- * writes of other values to get DMA buffers and send interrupts. */
-static ssize_t write(struct file *file, const char __user *input,
+ * writes of other values to send interrupts. */
+static ssize_t write(struct file *file, const char __user *in,
                     size_t size, loff_t *off)
 {
        /* Once the guest is initialized, we hold the "struct lguest" in the
         * file private data. */
        struct lguest *lg = file->private_data;
-       u32 req;
+       const unsigned long __user *input = (const unsigned long __user *)in;
+       unsigned long req;
 
        if (get_user(req, input) != 0)
                return -EFAULT;
-       input += sizeof(req);
+       input++;
 
        /* If you haven't initialized, you must do that first. */
        if (req != LHREQ_INITIALIZE && !lg)
@@ -287,13 +219,11 @@ static ssize_t write(struct file *file, const char __user *input,
 
        switch (req) {
        case LHREQ_INITIALIZE:
-               return initialize(file, (const u32 __user *)input);
-       case LHREQ_GETDMA:
-               return user_get_dma(lg, (const u32 __user *)input);
+               return initialize(file, input);
        case LHREQ_IRQ:
-               return user_send_irq(lg, (const u32 __user *)input);
+               return user_send_irq(lg, input);
        case LHREQ_BREAK:
-               return break_guest_out(lg, (const u32 __user *)input);
+               return break_guest_out(lg, input);
        default:
                return -EINVAL;
        }
@@ -319,8 +249,6 @@ static int close(struct inode *inode, struct file *file)
        mutex_lock(&lguest_lock);
        /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
        hrtimer_cancel(&lg->hrt);
-       /* Free any DMA buffers the Guest had bound. */
-       release_all_dma(lg);
        /* Free up the shadow page tables for the Guest. */
        free_guest_pagetable(lg);
        /* Now all the memory cleanups are done, it's safe to release the
index b7a924a..2a45f06 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/random.h>
 #include <linux/percpu.h>
 #include <asm/tlbflush.h>
+#include <asm/uaccess.h>
 #include "lg.h"
 
 /*M:008 We hold reference to pages, which prevents them from being swapped.
  *  (vii) Setting up the page tables initially.
  :*/
 
-/* Pages a 4k long, and each page table entry is 4 bytes long, giving us 1024
- * (or 2^10) entries per page. */
-#define PTES_PER_PAGE_SHIFT 10
-#define PTES_PER_PAGE (1 << PTES_PER_PAGE_SHIFT)
 
 /* 1024 entries in a page table page maps 1024 pages: 4MB.  The Switcher is
  * conveniently placed at the top 4MB, so it uses a separate, complete PTE
  * page.  */
-#define SWITCHER_PGD_INDEX (PTES_PER_PAGE - 1)
+#define SWITCHER_PGD_INDEX (PTRS_PER_PGD - 1)
 
 /* We actually need a separate PTE page for each CPU.  Remember that after the
  * Switcher code itself comes two pages for each CPU, and we don't want this
  * CPU's guest to see the pages of any other CPU. */
-static DEFINE_PER_CPU(spte_t *, switcher_pte_pages);
+static DEFINE_PER_CPU(pte_t *, switcher_pte_pages);
 #define switcher_pte_page(cpu) per_cpu(switcher_pte_pages, cpu)
 
 /*H:320 With our shadow and Guest types established, we need to deal with
  * them: the page table code is curly enough to need helper functions to keep
  * it clear and clean.
  *
- * The first helper takes a virtual address, and says which entry in the top
- * level page table deals with that address.  Since each top level entry deals
- * with 4M, this effectively divides by 4M. */
-static unsigned vaddr_to_pgd_index(unsigned long vaddr)
-{
-       return vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
-}
-
-/* There are two functions which return pointers to the shadow (aka "real")
+ * There are two functions which return pointers to the shadow (aka "real")
  * page tables.
  *
  * spgd_addr() takes the virtual address and returns a pointer to the top-level
  * page directory entry for that address.  Since we keep track of several page
  * tables, the "i" argument tells us which one we're interested in (it's
  * usually the current one). */
-static spgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
+static pgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
 {
-       unsigned int index = vaddr_to_pgd_index(vaddr);
+       unsigned int index = pgd_index(vaddr);
 
        /* We kill any Guest trying to touch the Switcher addresses. */
        if (index >= SWITCHER_PGD_INDEX) {
@@ -95,28 +84,28 @@ static spgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
 /* This routine then takes the PGD entry given above, which contains the
  * address of the PTE page.  It then returns a pointer to the PTE entry for the
  * given address. */
-static spte_t *spte_addr(struct lguest *lg, spgd_t spgd, unsigned long vaddr)
+static pte_t *spte_addr(struct lguest *lg, pgd_t spgd, unsigned long vaddr)
 {
-       spte_t *page = __va(spgd.pfn << PAGE_SHIFT);
+       pte_t *page = __va(pgd_pfn(spgd) << PAGE_SHIFT);
        /* You should never call this if the PGD entry wasn't valid */
-       BUG_ON(!(spgd.flags & _PAGE_PRESENT));
-       return &page[(vaddr >> PAGE_SHIFT) % PTES_PER_PAGE];
+       BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT));
+       return &page[(vaddr >> PAGE_SHIFT) % PTRS_PER_PTE];
 }
 
 /* These two functions just like the above two, except they access the Guest
  * page tables.  Hence they return a Guest address. */
 static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr)
 {
-       unsigned int index = vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
-       return lg->pgdirs[lg->pgdidx].cr3 + index * sizeof(gpgd_t);
+       unsigned int index = vaddr >> (PGDIR_SHIFT);
+       return lg->pgdirs[lg->pgdidx].gpgdir + index * sizeof(pgd_t);
 }
 
 static unsigned long gpte_addr(struct lguest *lg,
-                              gpgd_t gpgd, unsigned long vaddr)
+                              pgd_t gpgd, unsigned long vaddr)
 {
-       unsigned long gpage = gpgd.pfn << PAGE_SHIFT;
-       BUG_ON(!(gpgd.flags & _PAGE_PRESENT));
-       return gpage + ((vaddr>>PAGE_SHIFT) % PTES_PER_PAGE) * sizeof(gpte_t);
+       unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT;
+       BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT));
+       return gpage + ((vaddr>>PAGE_SHIFT) % PTRS_PER_PTE) * sizeof(pte_t);
 }
 
 /*H:350 This routine takes a page number given by the Guest and converts it to
@@ -149,53 +138,55 @@ static unsigned long get_pfn(unsigned long virtpfn, int write)
  * entry can be a little tricky.  The flags are (almost) the same, but the
  * Guest PTE contains a virtual page number: the CPU needs the real page
  * number. */
-static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write)
+static pte_t gpte_to_spte(struct lguest *lg, pte_t gpte, int write)
 {
-       spte_t spte;
-       unsigned long pfn;
+       unsigned long pfn, base, flags;
 
        /* The Guest sets the global flag, because it thinks that it is using
         * PGE.  We only told it to use PGE so it would tell us whether it was
         * flushing a kernel mapping or a userspace mapping.  We don't actually
         * use the global bit, so throw it away. */
-       spte.flags = (gpte.flags & ~_PAGE_GLOBAL);
+       flags = (pte_flags(gpte) & ~_PAGE_GLOBAL);
+
+       /* The Guest's pages are offset inside the Launcher. */
+       base = (unsigned long)lg->mem_base / PAGE_SIZE;
 
        /* We need a temporary "unsigned long" variable to hold the answer from
         * get_pfn(), because it returns 0xFFFFFFFF on failure, which wouldn't
         * fit in spte.pfn.  get_pfn() finds the real physical number of the
         * page, given the virtual number. */
-       pfn = get_pfn(gpte.pfn, write);
+       pfn = get_pfn(base + pte_pfn(gpte), write);
        if (pfn == -1UL) {
-               kill_guest(lg, "failed to get page %u", gpte.pfn);
+               kill_guest(lg, "failed to get page %lu", pte_pfn(gpte));
                /* When we destroy the Guest, we'll go through the shadow page
                 * tables and release_pte() them.  Make sure we don't think
                 * this one is valid! */
-               spte.flags = 0;
+               flags = 0;
        }
-       /* Now we assign the page number, and our shadow PTE is complete. */
-       spte.pfn = pfn;
-       return spte;
+       /* Now we assemble our shadow PTE from the page number and flags. */
+       return pfn_pte(pfn, __pgprot(flags));
 }
 
 /*H:460 And to complete the chain, release_pte() looks like this: */
-static void release_pte(spte_t pte)
+static void release_pte(pte_t pte)
 {
        /* Remember that get_user_pages() took a reference to the page, in
         * get_pfn()?  We have to put it back now. */
-       if (pte.flags & _PAGE_PRESENT)
-               put_page(pfn_to_page(pte.pfn));
+       if (pte_flags(pte) & _PAGE_PRESENT)
+               put_page(pfn_to_page(pte_pfn(pte)));
 }
 /*:*/
 
-static void check_gpte(struct lguest *lg, gpte_t gpte)
+static void check_gpte(struct lguest *lg, pte_t gpte)
 {
-       if ((gpte.flags & (_PAGE_PWT|_PAGE_PSE)) || gpte.pfn >= lg->pfn_limit)
+       if ((pte_flags(gpte) & (_PAGE_PWT|_PAGE_PSE))
+           || pte_pfn(gpte) >= lg->pfn_limit)
                kill_guest(lg, "bad page table entry");
 }
 
-static void check_gpgd(struct lguest *lg, gpgd_t gpgd)
+static void check_gpgd(struct lguest *lg, pgd_t gpgd)
 {
-       if ((gpgd.flags & ~_PAGE_TABLE) || gpgd.pfn >= lg->pfn_limit)
+       if ((pgd_flags(gpgd) & ~_PAGE_TABLE) || pgd_pfn(gpgd) >= lg->pfn_limit)
                kill_guest(lg, "bad page directory entry");
 }
 
@@ -211,21 +202,21 @@ static void check_gpgd(struct lguest *lg, gpgd_t gpgd)
  * true. */
 int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
 {
-       gpgd_t gpgd;
-       spgd_t *spgd;
+       pgd_t gpgd;
+       pgd_t *spgd;
        unsigned long gpte_ptr;
-       gpte_t gpte;
-       spte_t *spte;
+       pte_t gpte;
+       pte_t *spte;
 
        /* First step: get the top-level Guest page table entry. */
-       gpgd = mkgpgd(lgread_u32(lg, gpgd_addr(lg, vaddr)));
+       gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t);
        /* Toplevel not present?  We can't map it in. */
-       if (!(gpgd.flags & _PAGE_PRESENT))
+       if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
                return 0;
 
        /* Now look at the matching shadow entry. */
        spgd = spgd_addr(lg, lg->pgdidx, vaddr);
-       if (!(spgd->flags & _PAGE_PRESENT)) {
+       if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) {
                /* No shadow entry: allocate a new shadow PTE page. */
                unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
                /* This is not really the Guest's fault, but killing it is
@@ -238,34 +229,35 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
                check_gpgd(lg, gpgd);
                /* And we copy the flags to the shadow PGD entry.  The page
                 * number in the shadow PGD is the page we just allocated. */
-               spgd->raw.val = (__pa(ptepage) | gpgd.flags);
+               *spgd = __pgd(__pa(ptepage) | pgd_flags(gpgd));
        }
 
        /* OK, now we look at the lower level in the Guest page table: keep its
         * address, because we might update it later. */
        gpte_ptr = gpte_addr(lg, gpgd, vaddr);
-       gpte = mkgpte(lgread_u32(lg, gpte_ptr));
+       gpte = lgread(lg, gpte_ptr, pte_t);
 
        /* If this page isn't in the Guest page tables, we can't page it in. */
-       if (!(gpte.flags & _PAGE_PRESENT))
+       if (!(pte_flags(gpte) & _PAGE_PRESENT))
                return 0;
 
        /* Check they're not trying to write to a page the Guest wants
         * read-only (bit 2 of errcode == write). */
-       if ((errcode & 2) && !(gpte.flags & _PAGE_RW))
+       if ((errcode & 2) && !(pte_flags(gpte) & _PAGE_RW))
                return 0;
 
        /* User access to a kernel page? (bit 3 == user access) */
-       if ((errcode & 4) && !(gpte.flags & _PAGE_USER))
+       if ((errcode & 4) && !(pte_flags(gpte) & _PAGE_USER))
                return 0;
 
        /* Check that the Guest PTE flags are OK, and the page number is below
         * the pfn_limit (ie. not mapping the Launcher binary). */
        check_gpte(lg, gpte);
        /* Add the _PAGE_ACCESSED and (for a write) _PAGE_DIRTY flag */
-       gpte.flags |= _PAGE_ACCESSED;
+       gpte = pte_mkyoung(gpte);
+
        if (errcode & 2)
-               gpte.flags |= _PAGE_DIRTY;
+               gpte = pte_mkdirty(gpte);
 
        /* Get the pointer to the shadow PTE entry we're going to set. */
        spte = spte_addr(lg, *spgd, vaddr);
@@ -275,21 +267,18 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
 
        /* If this is a write, we insist that the Guest page is writable (the
         * final arg to gpte_to_spte()). */
-       if (gpte.flags & _PAGE_DIRTY)
+       if (pte_dirty(gpte))
                *spte = gpte_to_spte(lg, gpte, 1);
-       else {
+       else
                /* If this is a read, don't set the "writable" bit in the page
                 * table entry, even if the Guest says it's writable.  That way
                 * we come back here when a write does actually ocur, so we can
                 * update the Guest's _PAGE_DIRTY flag. */
-               gpte_t ro_gpte = gpte;
-               ro_gpte.flags &= ~_PAGE_RW;
-               *spte = gpte_to_spte(lg, ro_gpte, 0);
-       }
+               *spte = gpte_to_spte(lg, pte_wrprotect(gpte), 0);
 
        /* Finally, we write the Guest PTE entry back: we've set the
         * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */
-       lgwrite_u32(lg, gpte_ptr, gpte.raw.val);
+       lgwrite(lg, gpte_ptr, pte_t, gpte);
 
        /* We succeeded in mapping the page! */
        return 1;
@@ -305,17 +294,18 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
  * mapped by the shadow page tables, and is it writable? */
 static int page_writable(struct lguest *lg, unsigned long vaddr)
 {
-       spgd_t *spgd;
+       pgd_t *spgd;
        unsigned long flags;
 
        /* Look at the top level entry: is it present? */
        spgd = spgd_addr(lg, lg->pgdidx, vaddr);
-       if (!(spgd->flags & _PAGE_PRESENT))
+       if (!(pgd_flags(*spgd) & _PAGE_PRESENT))
                return 0;
 
        /* Check the flags on the pte entry itself: it must be present and
         * writable. */
-       flags = spte_addr(lg, *spgd, vaddr)->flags;
+       flags = pte_flags(*(spte_addr(lg, *spgd, vaddr)));
+
        return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
 }
 
@@ -329,22 +319,22 @@ void pin_page(struct lguest *lg, unsigned long vaddr)
 }
 
 /*H:450 If we chase down the release_pgd() code, it looks like this: */
-static void release_pgd(struct lguest *lg, spgd_t *spgd)
+static void release_pgd(struct lguest *lg, pgd_t *spgd)
 {
        /* If the entry's not present, there's nothing to release. */
-       if (spgd->flags & _PAGE_PRESENT) {
+       if (pgd_flags(*spgd) & _PAGE_PRESENT) {
                unsigned int i;
                /* Converting the pfn to find the actual PTE page is easy: turn
                 * the page number into a physical address, then convert to a
                 * virtual address (easy for kernel pages like this one). */
-               spte_t *ptepage = __va(spgd->pfn << PAGE_SHIFT);
+               pte_t *ptepage = __va(pgd_pfn(*spgd) << PAGE_SHIFT);
                /* For each entry in the page, we might need to release it. */
-               for (i = 0; i < PTES_PER_PAGE; i++)
+               for (i = 0; i < PTRS_PER_PTE; i++)
                        release_pte(ptepage[i]);
                /* Now we can free the page of PTEs */
                free_page((long)ptepage);
                /* And zero out the PGD entry we we never release it twice. */
-               spgd->raw.val = 0;
+               *spgd = __pgd(0);
        }
 }
 
@@ -356,7 +346,7 @@ static void flush_user_mappings(struct lguest *lg, int idx)
 {
        unsigned int i;
        /* Release every pgd entry up to the kernel's address. */
-       for (i = 0; i < vaddr_to_pgd_index(lg->page_offset); i++)
+       for (i = 0; i < pgd_index(lg->kernel_address); i++)
                release_pgd(lg, lg->pgdirs[idx].pgdir + i);
 }
 
@@ -369,6 +359,25 @@ void guest_pagetable_flush_user(struct lguest *lg)
 }
 /*:*/
 
+/* We walk down the guest page tables to get a guest-physical address */
+unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
+{
+       pgd_t gpgd;
+       pte_t gpte;
+
+       /* First step: get the top-level Guest page table entry. */
+       gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t);
+       /* Toplevel not present?  We can't map it in. */
+       if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
+               kill_guest(lg, "Bad address %#lx", vaddr);
+
+       gpte = lgread(lg, gpte_addr(lg, gpgd, vaddr), pte_t);
+       if (!(pte_flags(gpte) & _PAGE_PRESENT))
+               kill_guest(lg, "Bad address %#lx", vaddr);
+
+       return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
+}
+
 /* We keep several page tables.  This is a simple routine to find the page
  * table (if any) corresponding to this top-level address the Guest has given
  * us. */
@@ -376,7 +385,7 @@ static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
 {
        unsigned int i;
        for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
-               if (lg->pgdirs[i].cr3 == pgtable)
+               if (lg->pgdirs[i].gpgdir == pgtable)
                        break;
        return i;
 }
@@ -385,7 +394,7 @@ static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
  * allocate a new one (and so the kernel parts are not there), we set
  * blank_pgdir. */
 static unsigned int new_pgdir(struct lguest *lg,
-                             unsigned long cr3,
+                             unsigned long gpgdir,
                              int *blank_pgdir)
 {
        unsigned int next;
@@ -395,7 +404,7 @@ static unsigned int new_pgdir(struct lguest *lg,
        next = random32() % ARRAY_SIZE(lg->pgdirs);
        /* If it's never been allocated at all before, try now. */
        if (!lg->pgdirs[next].pgdir) {
-               lg->pgdirs[next].pgdir = (spgd_t *)get_zeroed_page(GFP_KERNEL);
+               lg->pgdirs[next].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
                /* If the allocation fails, just keep using the one we have */
                if (!lg->pgdirs[next].pgdir)
                        next = lg->pgdidx;
@@ -405,7 +414,7 @@ static unsigned int new_pgdir(struct lguest *lg,
                        *blank_pgdir = 1;
        }
        /* Record which Guest toplevel this shadows. */
-       lg->pgdirs[next].cr3 = cr3;
+       lg->pgdirs[next].gpgdir = gpgdir;
        /* Release all the non-kernel mappings. */
        flush_user_mappings(lg, next);
 
@@ -472,26 +481,27 @@ void guest_pagetable_clear_all(struct lguest *lg)
  * they set _PAGE_DIRTY then we can put a writable PTE entry in immediately.
  */
 static void do_set_pte(struct lguest *lg, int idx,
-                      unsigned long vaddr, gpte_t gpte)
+                      unsigned long vaddr, pte_t gpte)
 {
        /* Look up the matching shadow page directot entry. */
-       spgd_t *spgd = spgd_addr(lg, idx, vaddr);
+       pgd_t *spgd = spgd_addr(lg, idx, vaddr);
 
        /* If the top level isn't present, there's no entry to update. */
-       if (spgd->flags & _PAGE_PRESENT) {
+       if (pgd_flags(*spgd) & _PAGE_PRESENT) {
                /* Otherwise, we start by releasing the existing entry. */
-               spte_t *spte = spte_addr(lg, *spgd, vaddr);
+               pte_t *spte = spte_addr(lg, *spgd, vaddr);
                release_pte(*spte);
 
                /* If they're setting this entry as dirty or accessed, we might
                 * as well put that entry they've given us in now.  This shaves
                 * 10% off a copy-on-write micro-benchmark. */
-               if (gpte.flags & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
+               if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
                        check_gpte(lg, gpte);
-                       *spte = gpte_to_spte(lg, gpte, gpte.flags&_PAGE_DIRTY);
+                       *spte = gpte_to_spte(lg, gpte,
+                                            pte_flags(gpte) & _PAGE_DIRTY);
                } else
                        /* Otherwise we can demand_page() it in later. */
-                       spte->raw.val = 0;
+                       *spte = __pte(0);
        }
 }
 
@@ -506,18 +516,18 @@ static void do_set_pte(struct lguest *lg, int idx,
  * The benefit is that when we have to track a new page table, we can copy keep
  * all the kernel mappings.  This speeds up context switch immensely. */
 void guest_set_pte(struct lguest *lg,
-                  unsigned long cr3, unsigned long vaddr, gpte_t gpte)
+                  unsigned long gpgdir, unsigned long vaddr, pte_t gpte)
 {
        /* Kernel mappings must be changed on all top levels.  Slow, but
         * doesn't happen often. */
-       if (vaddr >= lg->page_offset) {
+       if (vaddr >= lg->kernel_address) {
                unsigned int i;
                for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
                        if (lg->pgdirs[i].pgdir)
                                do_set_pte(lg, i, vaddr, gpte);
        } else {
                /* Is this page table one we have a shadow for? */
-               int pgdir = find_pgdir(lg, cr3);
+               int pgdir = find_pgdir(lg, gpgdir);
                if (pgdir != ARRAY_SIZE(lg->pgdirs))
                        /* If so, do the update. */
                        do_set_pte(lg, pgdir, vaddr, gpte);
@@ -538,7 +548,7 @@ void guest_set_pte(struct lguest *lg,
  *
  * So with that in mind here's our code to to update a (top-level) PGD entry:
  */
-void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
+void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx)
 {
        int pgdir;
 
@@ -548,7 +558,7 @@ void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
                return;
 
        /* If they're talking about a page table we have a shadow for... */
-       pgdir = find_pgdir(lg, cr3);
+       pgdir = find_pgdir(lg, gpgdir);
        if (pgdir < ARRAY_SIZE(lg->pgdirs))
                /* ... throw it away. */
                release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
@@ -560,21 +570,34 @@ void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
  * its first page table is.  We set some things up here: */
 int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
 {
-       /* In flush_user_mappings() we loop from 0 to
-        * "vaddr_to_pgd_index(lg->page_offset)".  This assumes it won't hit
-        * the Switcher mappings, so check that now. */
-       if (vaddr_to_pgd_index(lg->page_offset) >= SWITCHER_PGD_INDEX)
-               return -EINVAL;
        /* We start on the first shadow page table, and give it a blank PGD
         * page. */
        lg->pgdidx = 0;
-       lg->pgdirs[lg->pgdidx].cr3 = pgtable;
-       lg->pgdirs[lg->pgdidx].pgdir = (spgd_t*)get_zeroed_page(GFP_KERNEL);
+       lg->pgdirs[lg->pgdidx].gpgdir = pgtable;
+       lg->pgdirs[lg->pgdidx].pgdir = (pgd_t*)get_zeroed_page(GFP_KERNEL);
        if (!lg->pgdirs[lg->pgdidx].pgdir)
                return -ENOMEM;
        return 0;
 }
 
+/* When the Guest calls LHCALL_LGUEST_INIT we do more setup. */
+void page_table_guest_data_init(struct lguest *lg)
+{
+       /* We get the kernel address: above this is all kernel memory. */
+       if (get_user(lg->kernel_address, &lg->lguest_data->kernel_address)
+           /* We tell the Guest that it can't use the top 4MB of virtual
+            * addresses used by the Switcher. */
+           || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
+           || put_user(lg->pgdirs[lg->pgdidx].gpgdir,&lg->lguest_data->pgdir))
+               kill_guest(lg, "bad guest page %p", lg->lguest_data);
+
+       /* In flush_user_mappings() we loop from 0 to
+        * "pgd_index(lg->kernel_address)".  This assumes it won't hit the
+        * Switcher mappings, so check that now. */
+       if (pgd_index(lg->kernel_address) >= SWITCHER_PGD_INDEX)
+               kill_guest(lg, "bad kernel address %#lx", lg->kernel_address);
+}
+
 /* When a Guest dies, our cleanup is fairly simple. */
 void free_guest_pagetable(struct lguest *lg)
 {
@@ -594,14 +617,14 @@ void free_guest_pagetable(struct lguest *lg)
  * for each CPU already set up, we just need to hook them in. */
 void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
 {
-       spte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
-       spgd_t switcher_pgd;
-       spte_t regs_pte;
+       pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
+       pgd_t switcher_pgd;
+       pte_t regs_pte;
 
        /* Make the last PGD entry for this Guest point to the Switcher's PTE
         * page for this CPU (with appropriate flags). */
-       switcher_pgd.pfn = __pa(switcher_pte_page) >> PAGE_SHIFT;
-       switcher_pgd.flags = _PAGE_KERNEL;
+       switcher_pgd = __pgd(__pa(switcher_pte_page) | _PAGE_KERNEL);
+
        lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
 
        /* We also change the Switcher PTE page.  When we're running the Guest,
@@ -611,10 +634,8 @@ void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
         * CPU's "struct lguest_pages": if we make sure the Guest's register
         * page is already mapped there, we don't have to copy them out
         * again. */
-       regs_pte.pfn = __pa(lg->regs_page) >> PAGE_SHIFT;
-       regs_pte.flags = _PAGE_KERNEL;
-       switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTES_PER_PAGE]
-               = regs_pte;
+       regs_pte = pfn_pte (__pa(lg->regs_page) >> PAGE_SHIFT, __pgprot(_PAGE_KERNEL));
+       switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTRS_PER_PTE] = regs_pte;
 }
 /*:*/
 
@@ -635,24 +656,25 @@ static __init void populate_switcher_pte_page(unsigned int cpu,
                                              unsigned int pages)
 {
        unsigned int i;
-       spte_t *pte = switcher_pte_page(cpu);
+       pte_t *pte = switcher_pte_page(cpu);
 
        /* The first entries are easy: they map the Switcher code. */
        for (i = 0; i < pages; i++) {
-               pte[i].pfn = page_to_pfn(switcher_page[i]);
-               pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+               pte[i] = mk_pte(switcher_page[i],
+                               __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED));
        }
 
        /* The only other thing we map is this CPU's pair of pages. */
        i = pages + cpu*2;
 
        /* First page (Guest registers) is writable from the Guest */
-       pte[i].pfn = page_to_pfn(switcher_page[i]);
-       pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW;
+       pte[i] = pfn_pte(page_to_pfn(switcher_page[i]),
+                        __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW));
+
        /* The second page contains the "struct lguest_ro_state", and is
         * read-only. */
-       pte[i+1].pfn = page_to_pfn(switcher_page[i+1]);
-       pte[i+1].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+       pte[i+1] = pfn_pte(page_to_pfn(switcher_page[i+1]),
+                          __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED));
 }
 
 /*H:510 At boot or module load time, init_pagetables() allocates and populates
@@ -662,7 +684,7 @@ __init int init_pagetables(struct page **switcher_page, unsigned int pages)
        unsigned int i;
 
        for_each_possible_cpu(i) {
-               switcher_pte_page(i) = (spte_t *)get_zeroed_page(GFP_KERNEL);
+               switcher_pte_page(i) = (pte_t *)get_zeroed_page(GFP_KERNEL);
                if (!switcher_pte_page(i)) {
                        free_switcher_pte_pages();
                        return -ENOMEM;
index 9b81119..c2434ec 100644 (file)
@@ -73,14 +73,14 @@ static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end)
                /* Segment descriptors contain a privilege level: the Guest is
                 * sometimes careless and leaves this as 0, even though it's
                 * running at privilege level 1.  If so, we fix it here. */
-               if ((lg->gdt[i].b & 0x00006000) == 0)
-                       lg->gdt[i].b |= (GUEST_PL << 13);
+               if ((lg->arch.gdt[i].b & 0x00006000) == 0)
+                       lg->arch.gdt[i].b |= (GUEST_PL << 13);
 
                /* Each descriptor has an "accessed" bit.  If we don't set it
                 * now, the CPU will try to set it when the Guest first loads
                 * that entry into a segment register.  But the GDT isn't
                 * writable by the Guest, so bad things can happen. */
-               lg->gdt[i].b |= 0x00000100;
+               lg->arch.gdt[i].b |= 0x00000100;
        }
 }
 
@@ -106,12 +106,12 @@ void setup_default_gdt_entries(struct lguest_ro_state *state)
 void setup_guest_gdt(struct lguest *lg)
 {
        /* Start with full 0-4G segments... */
-       lg->gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
-       lg->gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
+       lg->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
+       lg->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
        /* ...except the Guest is allowed to use them, so set the privilege
         * level appropriately in the flags. */
-       lg->gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
-       lg->gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
+       lg->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
+       lg->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
 }
 
 /* Like the IDT, we never simply use the GDT the Guest gives us.  We set up the
@@ -126,7 +126,7 @@ void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt)
        unsigned int i;
 
        for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++)
-               gdt[i] = lg->gdt[i];
+               gdt[i] = lg->arch.gdt[i];
 }
 
 /* This is the full version */
@@ -138,7 +138,7 @@ void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
         * replaced.  See ignored_gdt() above. */
        for (i = 0; i < GDT_ENTRIES; i++)
                if (!ignored_gdt(i))
-                       gdt[i] = lg->gdt[i];
+                       gdt[i] = lg->arch.gdt[i];
 }
 
 /* This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT). */
@@ -146,12 +146,12 @@ void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num)
 {
        /* We assume the Guest has the same number of GDT entries as the
         * Host, otherwise we'd have to dynamically allocate the Guest GDT. */
-       if (num > ARRAY_SIZE(lg->gdt))
+       if (num > ARRAY_SIZE(lg->arch.gdt))
                kill_guest(lg, "too many gdt entries %i", num);
 
        /* We read the whole thing in, then fix it up. */
-       lgread(lg, lg->gdt, table, num * sizeof(lg->gdt[0]));
-       fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->gdt));
+       __lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0]));
+       fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt));
        /* Mark that the GDT changed so the core knows it has to copy it again,
         * even if the Guest is run on the same CPU. */
        lg->changed |= CHANGED_GDT;
@@ -159,9 +159,9 @@ void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num)
 
 void guest_load_tls(struct lguest *lg, unsigned long gtls)
 {
-       struct desc_struct *tls = &lg->gdt[GDT_ENTRY_TLS_MIN];
+       struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN];
 
-       lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
+       __lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
        fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
        lg->changed |= CHANGED_GDT_TLS;
 }
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
new file mode 100644 (file)
index 0000000..9eed12d
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> IBM Corporation.
+ * Copyright (C) 2007, Jes Sorensen <jes@sgi.com> SGI.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/start_kernel.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/cpu.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <asm/paravirt.h>
+#include <asm/param.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/desc.h>
+#include <asm/setup.h>
+#include <asm/lguest.h>
+#include <asm/uaccess.h>
+#include <asm/i387.h>
+#include "../lg.h"
+
+static int cpu_had_pge;
+
+static struct {
+       unsigned long offset;
+       unsigned short segment;
+} lguest_entry;
+
+/* Offset from where switcher.S was compiled to where we've copied it */
+static unsigned long switcher_offset(void)
+{
+       return SWITCHER_ADDR - (unsigned long)start_switcher_text;
+}
+
+/* This cpu's struct lguest_pages. */
+static struct lguest_pages *lguest_pages(unsigned int cpu)
+{
+       return &(((struct lguest_pages *)
+                 (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
+}
+
+static DEFINE_PER_CPU(struct lguest *, last_guest);
+
+/*S:010
+ * We are getting close to the Switcher.
+ *
+ * Remember that each CPU has two pages which are visible to the Guest when it
+ * runs on that CPU.  This has to contain the state for that Guest: we copy the
+ * state in just before we run the Guest.
+ *
+ * Each Guest has "changed" flags which indicate what has changed in the Guest
+ * since it last ran.  We saw this set in interrupts_and_traps.c and
+ * segments.c.
+ */
+static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
+{
+       /* Copying all this data can be quite expensive.  We usually run the
+        * same Guest we ran last time (and that Guest hasn't run anywhere else
+        * meanwhile).  If that's not the case, we pretend everything in the
+        * Guest has changed. */
+       if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
+               __get_cpu_var(last_guest) = lg;
+               lg->last_pages = pages;
+               lg->changed = CHANGED_ALL;
+       }
+
+       /* These copies are pretty cheap, so we do them unconditionally: */
+       /* Save the current Host top-level page directory. */
+       pages->state.host_cr3 = __pa(current->mm->pgd);
+       /* Set up the Guest's page tables to see this CPU's pages (and no
+        * other CPU's pages). */
+       map_switcher_in_guest(lg, pages);
+       /* Set up the two "TSS" members which tell the CPU what stack to use
+        * for traps which do directly into the Guest (ie. traps at privilege
+        * level 1). */
+       pages->state.guest_tss.esp1 = lg->esp1;
+       pages->state.guest_tss.ss1 = lg->ss1;
+
+       /* Copy direct-to-Guest trap entries. */
+       if (lg->changed & CHANGED_IDT)
+               copy_traps(lg, pages->state.guest_idt, default_idt_entries);
+
+       /* Copy all GDT entries which the Guest can change. */
+       if (lg->changed & CHANGED_GDT)
+               copy_gdt(lg, pages->state.guest_gdt);
+       /* If only the TLS entries have changed, copy them. */
+       else if (lg->changed & CHANGED_GDT_TLS)
+               copy_gdt_tls(lg, pages->state.guest_gdt);
+
+       /* Mark the Guest as unchanged for next time. */
+       lg->changed = 0;
+}
+
+/* Finally: the code to actually call into the Switcher to run the Guest. */
+static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
+{
+       /* This is a dummy value we need for GCC's sake. */
+       unsigned int clobber;
+
+       /* Copy the guest-specific information into this CPU's "struct
+        * lguest_pages". */
+       copy_in_guest_info(lg, pages);
+
+       /* Set the trap number to 256 (impossible value).  If we fault while
+        * switching to the Guest (bad segment registers or bug), this will
+        * cause us to abort the Guest. */
+       lg->regs->trapnum = 256;
+
+       /* Now: we push the "eflags" register on the stack, then do an "lcall".
+        * This is how we change from using the kernel code segment to using
+        * the dedicated lguest code segment, as well as jumping into the
+        * Switcher.
+        *
+        * The lcall also pushes the old code segment (KERNEL_CS) onto the
+        * stack, then the address of this call.  This stack layout happens to
+        * exactly match the stack of an interrupt... */
+       asm volatile("pushf; lcall *lguest_entry"
+                    /* This is how we tell GCC that %eax ("a") and %ebx ("b")
+                     * are changed by this routine.  The "=" means output. */
+                    : "=a"(clobber), "=b"(clobber)
+                    /* %eax contains the pages pointer.  ("0" refers to the
+                     * 0-th argument above, ie "a").  %ebx contains the
+                     * physical address of the Guest's top-level page
+                     * directory. */
+                    : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
+                    /* We tell gcc that all these registers could change,
+                     * which means we don't have to save and restore them in
+                     * the Switcher. */
+                    : "memory", "%edx", "%ecx", "%edi", "%esi");
+}
+/*:*/
+
+/*H:040 This is the i386-specific code to setup and run the Guest.  Interrupts
+ * are disabled: we own the CPU. */
+void lguest_arch_run_guest(struct lguest *lg)
+{
+       /* Remember the awfully-named TS bit?  If the Guest has asked
+        * to set it we set it now, so we can trap and pass that trap
+        * to the Guest if it uses the FPU. */
+       if (lg->ts)
+               lguest_set_ts();
+
+       /* SYSENTER is an optimized way of doing system calls.  We
+        * can't allow it because it always jumps to privilege level 0.
+        * A normal Guest won't try it because we don't advertise it in
+        * CPUID, but a malicious Guest (or malicious Guest userspace
+        * program) could, so we tell the CPU to disable it before
+        * running the Guest. */
+       if (boot_cpu_has(X86_FEATURE_SEP))
+               wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
+
+       /* Now we actually run the Guest.  It will pop back out when
+        * something interesting happens, and we can examine its
+        * registers to see what it was doing. */
+       run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
+
+       /* The "regs" pointer contains two extra entries which are not
+        * really registers: a trap number which says what interrupt or
+        * trap made the switcher code come back, and an error code
+        * which some traps set.  */
+
+       /* If the Guest page faulted, then the cr2 register will tell
+        * us the bad virtual address.  We have to grab this now,
+        * because once we re-enable interrupts an interrupt could
+        * fault and thus overwrite cr2, or we could even move off to a
+        * different CPU. */
+       if (lg->regs->trapnum == 14)
+               lg->arch.last_pagefault = read_cr2();
+       /* Similarly, if we took a trap because the Guest used the FPU,
+        * we have to restore the FPU it expects to see. */
+       else if (lg->regs->trapnum == 7)
+               math_state_restore();
+
+       /* Restore SYSENTER if it's supposed to be on. */
+       if (boot_cpu_has(X86_FEATURE_SEP))
+               wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+}
+
+/*H:130 Our Guest is usually so well behaved; it never tries to do things it
+ * isn't allowed to.  Unfortunately, Linux's paravirtual infrastructure isn't
+ * quite complete, because it doesn't contain replacements for the Intel I/O
+ * instructions.  As a result, the Guest sometimes fumbles across one during
+ * the boot process as it probes for various things which are usually attached
+ * to a PC.
+ *
+ * When the Guest uses one of these instructions, we get trap #13 (General
+ * Protection Fault) and come here.  We see if it's one of those troublesome
+ * instructions and skip over it.  We return true if we did. */
+static int emulate_insn(struct lguest *lg)
+{
+       u8 insn;
+       unsigned int insnlen = 0, in = 0, shift = 0;
+       /* The eip contains the *virtual* address of the Guest's instruction:
+        * guest_pa just subtracts the Guest's page_offset. */
+       unsigned long physaddr = guest_pa(lg, lg->regs->eip);
+
+       /* This must be the Guest kernel trying to do something, not userspace!
+        * The bottom two bits of the CS segment register are the privilege
+        * level. */
+       if ((lg->regs->cs & 3) != GUEST_PL)
+               return 0;
+
+       /* Decoding x86 instructions is icky. */
+       insn = lgread(lg, physaddr, u8);
+
+       /* 0x66 is an "operand prefix".  It means it's using the upper 16 bits
+          of the eax register. */
+       if (insn == 0x66) {
+               shift = 16;
+               /* The instruction is 1 byte so far, read the next byte. */
+               insnlen = 1;
+               insn = lgread(lg, physaddr + insnlen, u8);
+       }
+
+       /* We can ignore the lower bit for the moment and decode the 4 opcodes
+        * we need to emulate. */
+       switch (insn & 0xFE) {
+       case 0xE4: /* in     <next byte>,%al */
+               insnlen += 2;
+               in = 1;
+               break;
+       case 0xEC: /* in     (%dx),%al */
+               insnlen += 1;
+               in = 1;
+               break;
+       case 0xE6: /* out    %al,<next byte> */
+               insnlen += 2;
+               break;
+       case 0xEE: /* out    %al,(%dx) */
+               insnlen += 1;
+               break;
+       default:
+               /* OK, we don't know what this is, can't emulate. */
+               return 0;
+       }
+
+       /* If it was an "IN" instruction, they expect the result to be read
+        * into %eax, so we change %eax.  We always return all-ones, which
+        * traditionally means "there's nothing there". */
+       if (in) {
+               /* Lower bit tells is whether it's a 16 or 32 bit access */
+               if (insn & 0x1)
+                       lg->regs->eax = 0xFFFFFFFF;
+               else
+                       lg->regs->eax |= (0xFFFF << shift);
+       }
+       /* Finally, we've "done" the instruction, so move past it. */
+       lg->regs->eip += insnlen;
+       /* Success! */
+       return 1;
+}
+
+/*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
+void lguest_arch_handle_trap(struct lguest *lg)
+{
+       switch (lg->regs->trapnum) {
+       case 13: /* We've intercepted a GPF. */
+                /* Check if this was one of those annoying IN or OUT
+                 * instructions which we need to emulate.  If so, we
+                 * just go back into the Guest after we've done it. */
+               if (lg->regs->errcode == 0) {
+                       if (emulate_insn(lg))
+                               return;
+               }
+               break;
+       case 14: /* We've intercepted a page fault. */
+                /* The Guest accessed a virtual address that wasn't
+                 * mapped.  This happens a lot: we don't actually set
+                 * up most of the page tables for the Guest at all when
+                 * we start: as it runs it asks for more and more, and
+                 * we set them up as required. In this case, we don't
+                 * even tell the Guest that the fault happened.
+                 *
+                 * The errcode tells whether this was a read or a
+                 * write, and whether kernel or userspace code. */
+               if (demand_page(lg, lg->arch.last_pagefault, lg->regs->errcode))
+                       return;
+
+                /* OK, it's really not there (or not OK): the Guest
+                 * needs to know.  We write out the cr2 value so it
+                 * knows where the fault occurred.
+                 *
+                 * Note that if the Guest were really messed up, this
+                 * could happen before it's done the INITIALIZE
+                 * hypercall, so lg->lguest_data will be NULL */
+               if (lg->lguest_data &&
+                   put_user(lg->arch.last_pagefault, &lg->lguest_data->cr2))
+                       kill_guest(lg, "Writing cr2");
+               break;
+       case 7: /* We've intercepted a Device Not Available fault. */
+               /* If the Guest doesn't want to know, we already
+                * restored the Floating Point Unit, so we just
+                * continue without telling it. */
+               if (!lg->ts)
+                       return;
+               break;
+       case 32 ... 255:
+               /* These values mean a real interrupt occurred, in which case
+                * the Host handler has already been run.  We just do a
+                * friendly check if another process should now be run, then
+                * return to run the Guest again */
+               cond_resched();
+               return;
+       case LGUEST_TRAP_ENTRY:
+               /* Our 'struct hcall_args' maps directly over our regs: we set
+                * up the pointer now to indicate a hypercall is pending. */
+               lg->hcall = (struct hcall_args *)lg->regs;
+               return;
+       }
+
+       /* We didn't handle the trap, so it needs to go to the Guest. */
+       if (!deliver_trap(lg, lg->regs->trapnum))
+               /* If the Guest doesn't have a handler (either it hasn't
+                * registered any yet, or it's one of the faults we don't let
+                * it handle), it dies with a cryptic error message. */
+               kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
+                          lg->regs->trapnum, lg->regs->eip,
+                          lg->regs->trapnum == 14 ? lg->arch.last_pagefault
+                          : lg->regs->errcode);
+}
+
+/* Now we can look at each of the routines this calls, in increasing order of
+ * complexity: do_hypercalls(), emulate_insn(), maybe_do_interrupt(),
+ * deliver_trap() and demand_page().  After all those, we'll be ready to
+ * examine the Switcher, and our philosophical understanding of the Host/Guest
+ * duality will be complete. :*/
+static void adjust_pge(void *on)
+{
+       if (on)
+               write_cr4(read_cr4() | X86_CR4_PGE);
+       else
+               write_cr4(read_cr4() & ~X86_CR4_PGE);
+}
+
+/*H:020 Now the Switcher is mapped and every thing else is ready, we need to do
+ * some more i386-specific initialization. */
+void __init lguest_arch_host_init(void)
+{
+       int i;
+
+       /* Most of the i386/switcher.S doesn't care that it's been moved; on
+        * Intel, jumps are relative, and it doesn't access any references to
+        * external code or data.
+        *
+        * The only exception is the interrupt handlers in switcher.S: their
+        * addresses are placed in a table (default_idt_entries), so we need to
+        * update the table with the new addresses.  switcher_offset() is a
+        * convenience function which returns the distance between the builtin
+        * switcher code and the high-mapped copy we just made. */
+       for (i = 0; i < IDT_ENTRIES; i++)
+               default_idt_entries[i] += switcher_offset();
+
+       /*
+        * Set up the Switcher's per-cpu areas.
+        *
+        * Each CPU gets two pages of its own within the high-mapped region
+        * (aka. "struct lguest_pages").  Much of this can be initialized now,
+        * but some depends on what Guest we are running (which is set up in
+        * copy_in_guest_info()).
+        */
+       for_each_possible_cpu(i) {
+               /* lguest_pages() returns this CPU's two pages. */
+               struct lguest_pages *pages = lguest_pages(i);
+               /* This is a convenience pointer to make the code fit one
+                * statement to a line. */
+               struct lguest_ro_state *state = &pages->state;
+
+               /* The Global Descriptor Table: the Host has a different one
+                * for each CPU.  We keep a descriptor for the GDT which says
+                * where it is and how big it is (the size is actually the last
+                * byte, not the size, hence the "-1"). */
+               state->host_gdt_desc.size = GDT_SIZE-1;
+               state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
+
+               /* All CPUs on the Host use the same Interrupt Descriptor
+                * Table, so we just use store_idt(), which gets this CPU's IDT
+                * descriptor. */
+               store_idt(&state->host_idt_desc);
+
+               /* The descriptors for the Guest's GDT and IDT can be filled
+                * out now, too.  We copy the GDT & IDT into ->guest_gdt and
+                * ->guest_idt before actually running the Guest. */
+               state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
+               state->guest_idt_desc.address = (long)&state->guest_idt;
+               state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
+               state->guest_gdt_desc.address = (long)&state->guest_gdt;
+
+               /* We know where we want the stack to be when the Guest enters
+                * the switcher: in pages->regs.  The stack grows upwards, so
+                * we start it at the end of that structure. */
+               state->guest_tss.esp0 = (long)(&pages->regs + 1);
+               /* And this is the GDT entry to use for the stack: we keep a
+                * couple of special LGUEST entries. */
+               state->guest_tss.ss0 = LGUEST_DS;
+
+               /* x86 can have a finegrained bitmap which indicates what I/O
+                * ports the process can use.  We set it to the end of our
+                * structure, meaning "none". */
+               state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
+
+               /* Some GDT entries are the same across all Guests, so we can
+                * set them up now. */
+               setup_default_gdt_entries(state);
+               /* Most IDT entries are the same for all Guests, too.*/
+               setup_default_idt_entries(state, default_idt_entries);
+
+               /* The Host needs to be able to use the LGUEST segments on this
+                * CPU, too, so put them in the Host GDT. */
+               get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+               get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+       }
+
+       /* In the Switcher, we want the %cs segment register to use the
+        * LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
+        * it will be undisturbed when we switch.  To change %cs and jump we
+        * need this structure to feed to Intel's "lcall" instruction. */
+       lguest_entry.offset = (long)switch_to_guest + switcher_offset();
+       lguest_entry.segment = LGUEST_CS;
+
+       /* Finally, we need to turn off "Page Global Enable".  PGE is an
+        * optimization where page table entries are specially marked to show
+        * they never change.  The Host kernel marks all the kernel pages this
+        * way because it's always present, even when userspace is running.
+        *
+        * Lguest breaks this: unbeknownst to the rest of the Host kernel, we
+        * switch to the Guest kernel.  If you don't disable this on all CPUs,
+        * you'll get really weird bugs that you'll chase for two days.
+        *
+        * I used to turn PGE off every time we switched to the Guest and back
+        * on when we return, but that slowed the Switcher down noticibly. */
+
+       /* We don't need the complexity of CPUs coming and going while we're
+        * doing this. */
+       lock_cpu_hotplug();
+       if (cpu_has_pge) { /* We have a broader idea of "global". */
+               /* Remember that this was originally set (for cleanup). */
+               cpu_had_pge = 1;
+               /* adjust_pge is a helper function which sets or unsets the PGE
+                * bit on its CPU, depending on the argument (0 == unset). */
+               on_each_cpu(adjust_pge, (void *)0, 0, 1);
+               /* Turn off the feature in the global feature set. */
+               clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+       }
+       unlock_cpu_hotplug();
+};
+/*:*/
+
+void __exit lguest_arch_host_fini(void)
+{
+       /* If we had PGE before we started, turn it back on now. */
+       lock_cpu_hotplug();
+       if (cpu_had_pge) {
+               set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+               /* adjust_pge's argument "1" means set PGE. */
+               on_each_cpu(adjust_pge, (void *)1, 0, 1);
+       }
+       unlock_cpu_hotplug();
+}
+
+
+/*H:122 The i386-specific hypercalls simply farm out to the right functions. */
+int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args)
+{
+       switch (args->arg0) {
+       case LHCALL_LOAD_GDT:
+               load_guest_gdt(lg, args->arg1, args->arg2);
+               break;
+       case LHCALL_LOAD_IDT_ENTRY:
+               load_guest_idt_entry(lg, args->arg1, args->arg2, args->arg3);
+               break;
+       case LHCALL_LOAD_TLS:
+               guest_load_tls(lg, args->arg1);
+               break;
+       default:
+               /* Bad Guest.  Bad! */
+               return -EIO;
+       }
+       return 0;
+}
+
+/*H:126 i386-specific hypercall initialization: */
+int lguest_arch_init_hypercalls(struct lguest *lg)
+{
+       u32 tsc_speed;
+
+       /* The pointer to the Guest's "struct lguest_data" is the only
+        * argument.  We check that address now. */
+       if (!lguest_address_ok(lg, lg->hcall->arg1, sizeof(*lg->lguest_data)))
+               return -EFAULT;
+
+       /* Having checked it, we simply set lg->lguest_data to point straight
+        * into the Launcher's memory at the right place and then use
+        * copy_to_user/from_user from now on, instead of lgread/write.  I put
+        * this in to show that I'm not immune to writing stupid
+        * optimizations. */
+       lg->lguest_data = lg->mem_base + lg->hcall->arg1;
+
+       /* We insist that the Time Stamp Counter exist and doesn't change with
+        * cpu frequency.  Some devious chip manufacturers decided that TSC
+        * changes could be handled in software.  I decided that time going
+        * backwards might be good for benchmarks, but it's bad for users.
+        *
+        * We also insist that the TSC be stable: the kernel detects unreliable
+        * TSCs for its own purposes, and we use that here. */
+       if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
+               tsc_speed = tsc_khz;
+       else
+               tsc_speed = 0;
+       if (put_user(tsc_speed, &lg->lguest_data->tsc_khz))
+               return -EFAULT;
+
+       /* The interrupt code might not like the system call vector. */
+       if (!check_syscall_vector(lg))
+               kill_guest(lg, "bad syscall vector");
+
+       return 0;
+}
+/* Now we've examined the hypercall code; our Guest can make requests.  There
+ * is one other way we can do things for the Guest, as we see in
+ * emulate_insn(). :*/
+
+/*L:030 lguest_arch_setup_regs()
+ *
+ * Most of the Guest's registers are left alone: we used get_zeroed_page() to
+ * allocate the structure, so they will be 0. */
+void lguest_arch_setup_regs(struct lguest *lg, unsigned long start)
+{
+       struct lguest_regs *regs = lg->regs;
+
+       /* There are four "segment" registers which the Guest needs to boot:
+        * The "code segment" register (cs) refers to the kernel code segment
+        * __KERNEL_CS, and the "data", "extra" and "stack" segment registers
+        * refer to the kernel data segment __KERNEL_DS.
+        *
+        * The privilege level is packed into the lower bits.  The Guest runs
+        * at privilege level 1 (GUEST_PL).*/
+       regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
+       regs->cs = __KERNEL_CS|GUEST_PL;
+
+       /* The "eflags" register contains miscellaneous flags.  Bit 1 (0x002)
+        * is supposed to always be "1".  Bit 9 (0x200) controls whether
+        * interrupts are enabled.  We always leave interrupts enabled while
+        * running the Guest. */
+       regs->eflags = 0x202;
+
+       /* The "Extended Instruction Pointer" register says where the Guest is
+        * running. */
+       regs->eip = start;
+
+       /* %esi points to our boot information, at physical address 0, so don't
+        * touch it. */
+       /* There are a couple of GDT entries the Guest expects when first
+        * booting. */
+
+       setup_guest_gdt(lg);
+}
similarity index 99%
rename from drivers/lguest/switcher.S
rename to drivers/lguest/x86/switcher_32.S
index 7c9c230..1010b90 100644 (file)
@@ -48,7 +48,8 @@
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 #include <asm/page.h>
-#include "lg.h"
+#include <asm/segment.h>
+#include <asm/lguest.h>
 
 // We mark the start of the code to copy
 // It's placed in .text tho it's never run here
@@ -132,6 +133,7 @@ ENTRY(switch_to_guest)
        // The Guest's register page has been mapped
        // Writable onto our %esp (stack) --
        // We can simply pop off all Guest regs.
+       popl    %eax
        popl    %ebx
        popl    %ecx
        popl    %edx
@@ -139,7 +141,6 @@ ENTRY(switch_to_guest)
        popl    %edi
        popl    %ebp
        popl    %gs
-       popl    %eax
        popl    %fs
        popl    %ds
        popl    %es
@@ -167,7 +168,6 @@ ENTRY(switch_to_guest)
        pushl   %es;                                                    \
        pushl   %ds;                                                    \
        pushl   %fs;                                                    \
-       pushl   %eax;                                                   \
        pushl   %gs;                                                    \
        pushl   %ebp;                                                   \
        pushl   %edi;                                                   \
@@ -175,6 +175,7 @@ ENTRY(switch_to_guest)
        pushl   %edx;                                                   \
        pushl   %ecx;                                                   \
        pushl   %ebx;                                                   \
+       pushl   %eax;                                                   \
        /* Our stack and our code are using segments                    \
         * Set in the TSS and IDT                                       \
         * Yet if we were to touch data we'd use                        \
index 927cb34..7c426d0 100644 (file)
@@ -274,7 +274,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
                        if (bitmap->offset < 0) {
                                /* DATA  BITMAP METADATA  */
                                if (bitmap->offset
-                                   + page->index * (PAGE_SIZE/512)
+                                   + (long)(page->index * (PAGE_SIZE/512))
                                    + size/512 > 0)
                                        /* bitmap runs in to metadata */
                                        return -EINVAL;
index 0eb5416..ac54f69 100644 (file)
@@ -348,16 +348,17 @@ static int crypt_convert(struct crypt_config *cc,
              ctx->idx_out < ctx->bio_out->bi_vcnt) {
                struct bio_vec *bv_in = bio_iovec_idx(ctx->bio_in, ctx->idx_in);
                struct bio_vec *bv_out = bio_iovec_idx(ctx->bio_out, ctx->idx_out);
-               struct scatterlist sg_in = {
-                       .page = bv_in->bv_page,
-                       .offset = bv_in->bv_offset + ctx->offset_in,
-                       .length = 1 << SECTOR_SHIFT
-               };
-               struct scatterlist sg_out = {
-                       .page = bv_out->bv_page,
-                       .offset = bv_out->bv_offset + ctx->offset_out,
-                       .length = 1 << SECTOR_SHIFT
-               };
+               struct scatterlist sg_in, sg_out;
+
+               sg_init_table(&sg_in, 1);
+               sg_set_page(&sg_in, bv_in->bv_page);
+               sg_in.offset = bv_in->bv_offset + ctx->offset_in;
+               sg_in.length = 1 << SECTOR_SHIFT;
+
+               sg_init_table(&sg_out, 1);
+               sg_set_page(&sg_out, bv_out->bv_page);
+               sg_out.offset = bv_out->bv_offset + ctx->offset_out;
+               sg_out.length = 1 << SECTOR_SHIFT;
 
                ctx->offset_in += sg_in.length;
                if (ctx->offset_in >= bv_in->bv_len) {
index 8ee181a..80a67d7 100644 (file)
@@ -376,7 +376,12 @@ static unsigned long get_stripe_work(struct stripe_head *sh)
                ack++;
 
        sh->ops.count -= ack;
-       BUG_ON(sh->ops.count < 0);
+       if (unlikely(sh->ops.count < 0)) {
+               printk(KERN_ERR "pending: %#lx ops.pending: %#lx ops.ack: %#lx "
+                       "ops.complete: %#lx\n", pending, sh->ops.pending,
+                       sh->ops.ack, sh->ops.complete);
+               BUG();
+       }
 
        return pending;
 }
@@ -550,8 +555,7 @@ static void ops_complete_biofill(void *stripe_head_ref)
                        }
                }
        }
-       clear_bit(STRIPE_OP_BIOFILL, &sh->ops.ack);
-       clear_bit(STRIPE_OP_BIOFILL, &sh->ops.pending);
+       set_bit(STRIPE_OP_BIOFILL, &sh->ops.complete);
 
        return_io(return_bi);
 
@@ -2893,6 +2897,13 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
        s.expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
        /* Now to look around and see what can be done */
 
+       /* clean-up completed biofill operations */
+       if (test_bit(STRIPE_OP_BIOFILL, &sh->ops.complete)) {
+               clear_bit(STRIPE_OP_BIOFILL, &sh->ops.pending);
+               clear_bit(STRIPE_OP_BIOFILL, &sh->ops.ack);
+               clear_bit(STRIPE_OP_BIOFILL, &sh->ops.complete);
+       }
+
        rcu_read_lock();
        for (i=disks; i--; ) {
                mdk_rdev_t *rdev;
index aefcf28..185e8a8 100644 (file)
@@ -1074,41 +1074,41 @@ EXPORT_SYMBOL_GPL(ir_codes_manli);
 /* Mike Baikov <mike@baikov.com> */
 IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE] = {
 
-       [ 0x21 ] = KEY_POWER,
-       [ 0x69 ] = KEY_TV,
-       [ 0x33 ] = KEY_0,
-       [ 0x51 ] = KEY_1,
-       [ 0x31 ] = KEY_2,
-       [ 0x71 ] = KEY_3,
-       [ 0x3b ] = KEY_4,
-       [ 0x58 ] = KEY_5,
-       [ 0x41 ] = KEY_6,
-       [ 0x48 ] = KEY_7,
-       [ 0x30 ] = KEY_8,
-       [ 0x53 ] = KEY_9,
-       [ 0x73 ] = KEY_AGAIN, /* LOOP */
-       [ 0x0a ] = KEY_AUDIO,
-       [ 0x61 ] = KEY_PRINT, /* PREVIEW */
-       [ 0x7a ] = KEY_VIDEO,
-       [ 0x20 ] = KEY_CHANNELUP,
-       [ 0x40 ] = KEY_CHANNELDOWN,
-       [ 0x18 ] = KEY_VOLUMEDOWN,
-       [ 0x50 ] = KEY_VOLUMEUP,
-       [ 0x10 ] = KEY_MUTE,
-       [ 0x4a ] = KEY_SEARCH,
-       [ 0x7b ] = KEY_SHUFFLE, /* SNAPSHOT */
-       [ 0x22 ] = KEY_RECORD,
-       [ 0x62 ] = KEY_STOP,
-       [ 0x78 ] = KEY_PLAY,
-       [ 0x39 ] = KEY_REWIND,
-       [ 0x59 ] = KEY_PAUSE,
-       [ 0x19 ] = KEY_FORWARD,
-       [ 0x09 ] = KEY_ZOOM,
-
-       [ 0x52 ] = KEY_F21, /* LIVE TIMESHIFT */
-       [ 0x1a ] = KEY_F22, /* MIN TIMESHIFT */
-       [ 0x3a ] = KEY_F23, /* TIMESHIFT */
-       [ 0x70 ] = KEY_F24, /* NORMAL TIMESHIFT */
+       [ 0x11 ] = KEY_POWER,
+       [ 0x35 ] = KEY_TV,
+       [ 0x1b ] = KEY_0,
+       [ 0x29 ] = KEY_1,
+       [ 0x19 ] = KEY_2,
+       [ 0x39 ] = KEY_3,
+       [ 0x1f ] = KEY_4,
+       [ 0x2c ] = KEY_5,
+       [ 0x21 ] = KEY_6,
+       [ 0x24 ] = KEY_7,
+       [ 0x18 ] = KEY_8,
+       [ 0x2b ] = KEY_9,
+       [ 0x3b ] = KEY_AGAIN, /* LOOP */
+       [ 0x06 ] = KEY_AUDIO,
+       [ 0x31 ] = KEY_PRINT, /* PREVIEW */
+       [ 0x3e ] = KEY_VIDEO,
+       [ 0x10 ] = KEY_CHANNELUP,
+       [ 0x20 ] = KEY_CHANNELDOWN,
+       [ 0x0c ] = KEY_VOLUMEDOWN,
+       [ 0x28 ] = KEY_VOLUMEUP,
+       [ 0x08 ] = KEY_MUTE,
+       [ 0x26 ] = KEY_SEARCH, /*SCAN*/
+       [ 0x3f ] = KEY_SHUFFLE, /* SNAPSHOT */
+       [ 0x12 ] = KEY_RECORD,
+       [ 0x32 ] = KEY_STOP,
+       [ 0x3c ] = KEY_PLAY,
+       [ 0x1d ] = KEY_REWIND,
+       [ 0x2d ] = KEY_PAUSE,
+       [ 0x0d ] = KEY_FORWARD,
+       [ 0x05 ] = KEY_ZOOM,  /*FULL*/
+
+       [ 0x2a ] = KEY_F21, /* LIVE TIMESHIFT */
+       [ 0x0e ] = KEY_F22, /* MIN TIMESHIFT */
+       [ 0x1e ] = KEY_F23, /* TIMESHIFT */
+       [ 0x38 ] = KEY_F24, /* NORMAL TIMESHIFT */
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_gotview7135);
index 365a221..2b1f8b4 100644 (file)
@@ -112,12 +112,13 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
        sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
        if (NULL == sglist)
                return NULL;
+       sg_init_table(sglist, nr_pages);
        for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
                pg = vmalloc_to_page(virt);
                if (NULL == pg)
                        goto err;
                BUG_ON(PageHighMem(pg));
-               sglist[i].page   = pg;
+               sg_set_page(&sglist[i], pg);
                sglist[i].length = PAGE_SIZE;
        }
        return sglist;
index a05e5c1..db08b0a 100644 (file)
@@ -345,7 +345,9 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct dvb_demux *demux = dvbdmxfeed->demux;
        struct cinergyt2 *cinergyt2 = demux->priv;
 
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending)
+               return -EAGAIN;
+       if (mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (cinergyt2->streaming == 0)
@@ -361,7 +363,9 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct dvb_demux *demux = dvbdmxfeed->demux;
        struct cinergyt2 *cinergyt2 = demux->priv;
 
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending)
+               return -EAGAIN;
+       if (mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (--cinergyt2->streaming == 0)
@@ -481,12 +485,16 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       int err = -ERESTARTSYS;
+       int err = -EAGAIN;
 
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
+       if (cinergyt2->disconnect_pending)
+               goto out;
+       err = mutex_lock_interruptible(&cinergyt2->wq_sem);
+       if (err)
                goto out;
 
-       if (mutex_lock_interruptible(&cinergyt2->sem))
+       err = mutex_lock_interruptible(&cinergyt2->sem);
+       if (err)
                goto out_unlock1;
 
        if ((err = dvb_generic_open(inode, file)))
@@ -550,7 +558,9 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
        unsigned int mask = 0;
 
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending)
+               return -EAGAIN;
+       if (mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        poll_wait(file, &cinergyt2->poll_wq, wait);
@@ -625,7 +635,9 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
                if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
                        return -EFAULT;
 
-               if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
+               if (cinergyt2->disconnect_pending)
+                       return -EAGAIN;
+               if (mutex_lock_interruptible(&cinergyt2->sem))
                        return -ERESTARTSYS;
 
                param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -996,7 +1008,9 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
 {
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
+       if (cinergyt2->disconnect_pending)
+               return -EAGAIN;
+       if (mutex_lock_interruptible(&cinergyt2->wq_sem))
                return -ERESTARTSYS;
 
        cinergyt2_suspend_rc(cinergyt2);
@@ -1017,16 +1031,18 @@ static int cinergyt2_resume (struct usb_interface *intf)
 {
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
        struct dvbt_set_parameters_msg *param = &cinergyt2->param;
-       int err = -ERESTARTSYS;
+       int err = -EAGAIN;
 
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
+       if (cinergyt2->disconnect_pending)
+               goto out;
+       err = mutex_lock_interruptible(&cinergyt2->wq_sem);
+       if (err)
                goto out;
 
-       if (mutex_lock_interruptible(&cinergyt2->sem))
+       err = mutex_lock_interruptible(&cinergyt2->sem);
+       if (err)
                goto out_unlock1;
 
-       err = 0;
-
        if (!cinergyt2->sleeping) {
                cinergyt2_sleep(cinergyt2, 0);
                cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0);
index 084a508..89437fd 100644 (file)
@@ -972,7 +972,7 @@ static int dvb_ca_en50221_thread(void *data)
        /* main loop */
        while (!kthread_should_stop()) {
                /* sleep for a bit */
-               while (!ca->wakeup) {
+               if (!ca->wakeup) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule_timeout(ca->delay);
                        if (kthread_should_stop())
index e8c4a86..58452b5 100644 (file)
@@ -828,7 +828,7 @@ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
 #define DIB0700_DEFAULT_DEVICE_PROPERTIES \
        .caps              = DVB_USB_IS_AN_I2C_ADAPTER, \
        .usb_ctrl          = DEVICE_SPECIFIC, \
-       .firmware          = "dvb-usb-dib0700-03-pre1.fw", \
+       .firmware          = "dvb-usb-dib0700-1.10.fw", \
        .download_firmware = dib0700_download_firmware, \
        .no_reconnect      = 1, \
        .size_of_priv      = sizeof(struct dib0700_state), \
index c7c9d1d..3ae56fe 100644 (file)
@@ -229,7 +229,6 @@ static struct video_device pcm20_radio = {
        .owner          = THIS_MODULE,
        .name           = "Miro PCM 20 radio",
        .type           = VID_TYPE_TUNER,
-       .hardware       = VID_HARDWARE_RTRACK,
        .fops           = &pcm20_fops,
        .priv           = &pcm20_unit
 };
index 0c963db..5e4b9dd 100644 (file)
@@ -554,7 +554,6 @@ static struct video_device gemtek_radio = {
        .owner                  = THIS_MODULE,
        .name                   = "GemTek Radio card",
        .type                   = VID_TYPE_TUNER,
-       .hardware               = VID_HARDWARE_GEMTEK,
        .fops                   = &gemtek_fops,
        .vidioc_querycap        = vidioc_querycap,
        .vidioc_g_tuner         = vidioc_g_tuner,
index 19e9929..c94a4d0 100644 (file)
@@ -755,7 +755,6 @@ static struct video_device ar_template = {
        .owner          = THIS_MODULE,
        .name           = "Colour AR VGA",
        .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_ARV,
        .fops           = &ar_fops,
        .release        = ar_release,
        .minor          = -1,
index 7a332b3..9feeb63 100644 (file)
@@ -3877,7 +3877,6 @@ static struct video_device bttv_video_template =
        .name     = "UNSET",
        .type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
                    VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-       .hardware = VID_HARDWARE_BT848,
        .fops     = &bttv_fops,
        .minor    = -1,
 };
@@ -3886,7 +3885,6 @@ static struct video_device bttv_vbi_template =
 {
        .name     = "bt848/878 vbi",
        .type     = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
-       .hardware = VID_HARDWARE_BT848,
        .fops     = &bttv_fops,
        .minor    = -1,
 };
@@ -4034,7 +4032,6 @@ static struct video_device radio_template =
 {
        .name     = "bt848/878 radio",
        .type     = VID_TYPE_TUNER,
-       .hardware = VID_HARDWARE_BT848,
        .fops     = &radio_fops,
        .minor    = -1,
 };
index 7f7e3d3..5842352 100644 (file)
@@ -899,7 +899,6 @@ static struct video_device qcam_template=
        .owner          = THIS_MODULE,
        .name           = "Connectix Quickcam",
        .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_QCAM_BW,
        .fops           = &qcam_fops,
 };
 
index f76c6a6..cf1546b 100644 (file)
@@ -699,7 +699,6 @@ static struct video_device qcam_template=
        .owner          = THIS_MODULE,
        .name           = "Colour QuickCam",
        .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_QCAM_C,
        .fops           = &qcam_fops,
 };
 
index a1d02e5..7c630f5 100644 (file)
@@ -65,10 +65,6 @@ MODULE_PARM_DESC(colorspace_conv,
 
 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
 
-#ifndef VID_HARDWARE_CPIA
-#define VID_HARDWARE_CPIA 24    /* FIXME -> from linux/videodev.h */
-#endif
-
 #define CPIA_MODULE_CPIA                       (0<<5)
 #define CPIA_MODULE_SYSTEM                     (1<<5)
 #define CPIA_MODULE_VP_CTRL                    (5<<5)
@@ -3804,7 +3800,6 @@ static struct video_device cpia_template = {
        .owner          = THIS_MODULE,
        .name           = "CPiA Camera",
        .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_CPIA,
        .fops           = &cpia_fops,
 };
 
index e3aaba1..e378abe 100644 (file)
@@ -86,10 +86,6 @@ MODULE_LICENSE("GPL");
 
 #define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
 
-#ifndef VID_HARDWARE_CPIA2
-#error "VID_HARDWARE_CPIA2 should have been defined in linux/videodev.h"
-#endif
-
 struct control_menu_info {
        int value;
        char name[32];
@@ -1942,7 +1938,6 @@ static struct video_device cpia2_template = {
        .type=          VID_TYPE_CAPTURE,
        .type2 =        V4L2_CAP_VIDEO_CAPTURE |
                        V4L2_CAP_STREAMING,
-       .hardware=      VID_HARDWARE_CPIA2,
        .minor=         -1,
        .fops=          &fops_template,
        .release=       video_device_release,
index af16505..3cdd136 100644 (file)
@@ -793,7 +793,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
                       dev->pci->subsystem_device);
 
                cx23885_devcount--;
-               goto fail_free;
+               return -ENODEV;
        }
 
        /* PCIe stuff */
@@ -835,10 +835,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        }
 
        return 0;
-
-fail_free:
-       kfree(dev);
-       return -ENODEV;
 }
 
 void cx23885_dev_unregister(struct cx23885_dev *dev)
index 141dadf..40ffd7a 100644 (file)
@@ -39,6 +39,7 @@
 #include <sound/pcm_params.h>
 #include <sound/control.h>
 #include <sound/initval.h>
+#include <sound/tlv.h>
 
 #include "cx88.h"
 #include "cx88-reg.h"
@@ -82,6 +83,7 @@ typedef struct cx88_audio_dev snd_cx88_card_t;
 
 
 
+
 /****************************************************************************
                        Module global static vars
  ****************************************************************************/
@@ -545,8 +547,8 @@ static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
 /****************************************************************************
                                CONTROL INTERFACE
  ****************************************************************************/
-static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol,
-                                       struct snd_ctl_elem_info *info)
+static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *info)
 {
        info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        info->count = 2;
@@ -556,9 +558,8 @@ static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-/* OK - TODO: test it */
-static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol,
-                                      struct snd_ctl_elem_value *value)
+static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
 {
        snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
        struct cx88_core *core=chip->core;
@@ -573,8 +574,8 @@ static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol,
 }
 
 /* OK - TODO: test it */
-static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol,
-                                      struct snd_ctl_elem_value *value)
+static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
 {
        snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
        struct cx88_core *core=chip->core;
@@ -605,14 +606,67 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol,
        return changed;
 }
 
-static struct snd_kcontrol_new snd_cx88_capture_volume = {
+static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
+
+static struct snd_kcontrol_new snd_cx88_volume = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                 SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+       .name = "Playback Volume",
+       .info = snd_cx88_volume_info,
+       .get = snd_cx88_volume_get,
+       .put = snd_cx88_volume_put,
+       .tlv.p = snd_cx88_db_scale,
+};
+
+static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+       struct cx88_core *core = chip->core;
+       u32 bit = kcontrol->private_value;
+
+       value->value.integer.value[0] = !(cx_read(AUD_VOL_CTL) & bit);
+       return 0;
+}
+
+static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *value)
+{
+       snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+       struct cx88_core *core = chip->core;
+       u32 bit = kcontrol->private_value;
+       int ret = 0;
+       u32 vol;
+
+       spin_lock_irq(&chip->reg_lock);
+       vol = cx_read(AUD_VOL_CTL);
+       if (value->value.integer.value[0] != !(vol & bit)) {
+               vol ^= bit;
+               cx_write(AUD_VOL_CTL, vol);
+               ret = 1;
+       }
+       spin_unlock_irq(&chip->reg_lock);
+       return ret;
+}
+
+static struct snd_kcontrol_new snd_cx88_dac_switch = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Volume",
-       .info = snd_cx88_capture_volume_info,
-       .get = snd_cx88_capture_volume_get,
-       .put = snd_cx88_capture_volume_put,
+       .name = "Playback Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = snd_cx88_switch_get,
+       .put = snd_cx88_switch_put,
+       .private_value = (1<<8),
 };
 
+static struct snd_kcontrol_new snd_cx88_source_switch = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = snd_cx88_switch_get,
+       .put = snd_cx88_switch_put,
+       .private_value = (1<<6),
+};
 
 /****************************************************************************
                        Basic Flow for Sound Devices
@@ -762,7 +816,13 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
        if (err < 0)
                goto error;
 
-       err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip));
+       err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_volume, chip));
+       if (err < 0)
+               goto error;
+       err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_dac_switch, chip));
+       if (err < 0)
+               goto error;
+       err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_source_switch, chip));
        if (err < 0)
                goto error;
 
index 6d6f504..f33f0b4 100644 (file)
@@ -527,44 +527,6 @@ static void blackbird_codec_settings(struct cx8802_dev *dev)
        cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
 }
 
-static struct v4l2_mpeg_compression default_mpeg_params = {
-       .st_type          = V4L2_MPEG_PS_2,
-       .st_bitrate       = {
-               .mode     = V4L2_BITRATE_CBR,
-               .min      = 0,
-               .target   = 0,
-               .max      = 0
-       },
-       .ts_pid_pmt       = 16,
-       .ts_pid_audio     = 260,
-       .ts_pid_video     = 256,
-       .ts_pid_pcr       = 259,
-       .ps_size          = 0,
-       .au_type          = V4L2_MPEG_AU_2_II,
-       .au_bitrate       = {
-               .mode     = V4L2_BITRATE_CBR,
-               .min      = 224,
-               .target   = 224,
-               .max      = 224
-       },
-       .au_sample_rate    = 48000,
-       .au_pesid          = 0,
-       .vi_type           = V4L2_MPEG_VI_2,
-       .vi_aspect_ratio   = V4L2_MPEG_ASPECT_4_3,
-       .vi_bitrate        = {
-               .mode      = V4L2_BITRATE_CBR,
-               .min       = 4000,
-               .target    = 4500,
-               .max       = 6000
-       },
-       .vi_frame_rate     = 25,
-       .vi_frames_per_gop = 12,
-       .vi_bframes_count  = 2,
-       .vi_pesid          = 0,
-       .closed_gops       = 1,
-       .pulldown          = 0
-};
-
 static int blackbird_initialize_codec(struct cx8802_dev *dev)
 {
        struct cx88_core *core = dev->core;
@@ -852,23 +814,6 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
        return videobuf_streamoff(&fh->mpegq);
 }
 
-static int vidioc_g_mpegcomp (struct file *file, void *fh,
-                             struct v4l2_mpeg_compression *f)
-{
-       printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
-                               "Replace with VIDIOC_G_EXT_CTRLS!");
-       memcpy(f,&default_mpeg_params,sizeof(*f));
-       return 0;
-}
-
-static int vidioc_s_mpegcomp (struct file *file, void *fh,
-                             struct v4l2_mpeg_compression *f)
-{
-       printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
-                               "Replace with VIDIOC_S_EXT_CTRLS!");
-       return 0;
-}
-
 static int vidioc_g_ext_ctrls (struct file *file, void *priv,
                               struct v4l2_ext_controls *f)
 {
@@ -1216,8 +1161,6 @@ static struct video_device cx8802_mpeg_template =
        .vidioc_dqbuf         = vidioc_dqbuf,
        .vidioc_streamon      = vidioc_streamon,
        .vidioc_streamoff     = vidioc_streamoff,
-       .vidioc_g_mpegcomp    = vidioc_g_mpegcomp,
-       .vidioc_s_mpegcomp    = vidioc_s_mpegcomp,
        .vidioc_g_ext_ctrls   = vidioc_g_ext_ctrls,
        .vidioc_s_ext_ctrls   = vidioc_s_ext_ctrls,
        .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
index d16e5c6..fce19ca 100644 (file)
@@ -475,8 +475,9 @@ static int dvb_register(struct cx8802_dev *dev)
                break;
        case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
 #if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+               /* MT352 is on a secondary I2C bus made from some GPIO lines */
                dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
-                       &((struct vp3054_i2c_state *)dev->card_priv)->adap);
+                                              &dev->vp3054->adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
                                   &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
index a652f29..448c673 100644 (file)
@@ -79,7 +79,8 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 {
        struct cx88_core *core = dev->core;
 
-       dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
+       dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n",
+               buf->vb.width, buf->vb.height, buf->vb.field);
 
        /* setup fifo + format */
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -177,7 +178,6 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
                                struct cx88_dmaqueue *q)
 {
        struct cx88_buffer *buf;
-       struct list_head *item;
 
        dprintk( 1, "cx8802_restart_queue\n" );
        if (list_empty(&q->active))
@@ -223,10 +223,8 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
        dprintk(2,"restart_queue [%p/%d]: restart dma\n",
                buf, buf->vb.i);
        cx8802_start_dma(dev, q, buf);
-       list_for_each(item,&q->active) {
-               buf = list_entry(item, struct cx88_buffer, vb.queue);
+       list_for_each_entry(buf, &q->active, vb.queue)
                buf->count = q->count++;
-       }
        mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
        return 0;
 }
@@ -572,42 +570,29 @@ int cx8802_resume_common(struct pci_dev *pci_dev)
        return 0;
 }
 
+#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \
+    defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE)
 struct cx8802_dev * cx8802_get_device(struct inode *inode)
 {
        int minor = iminor(inode);
-       struct cx8802_dev *h = NULL;
-       struct list_head *list;
+       struct cx8802_dev *dev;
 
-       list_for_each(list,&cx8802_devlist) {
-               h = list_entry(list, struct cx8802_dev, devlist);
-               if (h->mpeg_dev && h->mpeg_dev->minor == minor)
-                       return h;
-       }
+       list_for_each_entry(dev, &cx8802_devlist, devlist)
+               if (dev->mpeg_dev && dev->mpeg_dev->minor == minor)
+                       return dev;
 
        return NULL;
 }
+EXPORT_SYMBOL(cx8802_get_device);
+#endif
 
 struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype)
 {
-       struct cx8802_dev *h = NULL;
-       struct cx8802_driver *d = NULL;
-       struct list_head *list;
-       struct list_head *list2;
-
-       list_for_each(list,&cx8802_devlist) {
-               h = list_entry(list, struct cx8802_dev, devlist);
-               if (h != dev)
-                       continue;
-
-               list_for_each(list2, &h->drvlist.devlist) {
-                       d = list_entry(list2, struct cx8802_driver, devlist);
+       struct cx8802_driver *d;
 
-                       /* only unregister the correct driver type */
-                       if (d->type_id == btype) {
-                               return d;
-                       }
-               }
-       }
+       list_for_each_entry(d, &dev->drvlist, drvlist)
+               if (d->type_id == btype)
+                       return d;
 
        return NULL;
 }
@@ -671,10 +656,9 @@ static int cx8802_check_driver(struct cx8802_driver *drv)
 
 int cx8802_register_driver(struct cx8802_driver *drv)
 {
-       struct cx8802_dev *h;
+       struct cx8802_dev *dev;
        struct cx8802_driver *driver;
-       struct list_head *list;
-       int err = 0, i = 0;
+       int err, i = 0;
 
        printk(KERN_INFO
               "cx88/2: registering cx8802 driver, type: %s access: %s\n",
@@ -686,14 +670,12 @@ int cx8802_register_driver(struct cx8802_driver *drv)
                return err;
        }
 
-       list_for_each(list,&cx8802_devlist) {
-               h = list_entry(list, struct cx8802_dev, devlist);
-
+       list_for_each_entry(dev, &cx8802_devlist, devlist) {
                printk(KERN_INFO
                       "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
-                      h->core->name, h->pci->subsystem_vendor,
-                      h->pci->subsystem_device, h->core->board.name,
-                      h->core->boardnr);
+                      dev->core->name, dev->pci->subsystem_vendor,
+                      dev->pci->subsystem_device, dev->core->board.name,
+                      dev->core->boardnr);
 
                /* Bring up a new struct for each driver instance */
                driver = kzalloc(sizeof(*drv),GFP_KERNEL);
@@ -701,7 +683,7 @@ int cx8802_register_driver(struct cx8802_driver *drv)
                        return -ENOMEM;
 
                /* Snapshot of the driver registration data */
-               drv->core = h->core;
+               drv->core = dev->core;
                drv->suspend = cx8802_suspend_common;
                drv->resume = cx8802_resume_common;
                drv->request_acquire = cx8802_request_acquire;
@@ -712,49 +694,38 @@ int cx8802_register_driver(struct cx8802_driver *drv)
                if (err == 0) {
                        i++;
                        mutex_lock(&drv->core->lock);
-                       list_add_tail(&driver->devlist,&h->drvlist.devlist);
+                       list_add_tail(&driver->drvlist, &dev->drvlist);
                        mutex_unlock(&drv->core->lock);
                } else {
                        printk(KERN_ERR
                               "%s/2: cx8802 probe failed, err = %d\n",
-                              h->core->name, err);
+                              dev->core->name, err);
                }
 
        }
-       if (i == 0)
-               err = -ENODEV;
-       else
-               err = 0;
 
-       return err;
+       return i ? 0 : -ENODEV;
 }
 
 int cx8802_unregister_driver(struct cx8802_driver *drv)
 {
-       struct cx8802_dev *h;
-       struct cx8802_driver *d;
-       struct list_head *list;
-       struct list_head *list2, *q;
-       int err = 0, i = 0;
+       struct cx8802_dev *dev;
+       struct cx8802_driver *d, *dtmp;
+       int err = 0;
 
        printk(KERN_INFO
               "cx88/2: unregistering cx8802 driver, type: %s access: %s\n",
               drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
               drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
 
-       list_for_each(list,&cx8802_devlist) {
-               i++;
-               h = list_entry(list, struct cx8802_dev, devlist);
-
+       list_for_each_entry(dev, &cx8802_devlist, devlist) {
                printk(KERN_INFO
                       "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
-                      h->core->name, h->pci->subsystem_vendor,
-                      h->pci->subsystem_device, h->core->board.name,
-                      h->core->boardnr);
-
-               list_for_each_safe(list2, q, &h->drvlist.devlist) {
-                       d = list_entry(list2, struct cx8802_driver, devlist);
+                      dev->core->name, dev->pci->subsystem_vendor,
+                      dev->pci->subsystem_device, dev->core->board.name,
+                      dev->core->boardnr);
 
+               list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) {
                        /* only unregister the correct driver type */
                        if (d->type_id != drv->type_id)
                                continue;
@@ -762,12 +733,12 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
                        err = d->remove(d);
                        if (err == 0) {
                                mutex_lock(&drv->core->lock);
-                               list_del(list2);
+                               list_del(&d->drvlist);
                                mutex_unlock(&drv->core->lock);
+                               kfree(d);
                        } else
                                printk(KERN_ERR "%s/2: cx8802 driver remove "
-                                      "failed (%d)\n", h->core->name, err);
-
+                                      "failed (%d)\n", dev->core->name, err);
                }
 
        }
@@ -805,7 +776,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
        if (err != 0)
                goto fail_free;
 
-       INIT_LIST_HEAD(&dev->drvlist.devlist);
+       INIT_LIST_HEAD(&dev->drvlist);
        list_add_tail(&dev->devlist,&cx8802_devlist);
 
        /* Maintain a reference so cx88-video can query the 8802 device. */
@@ -825,23 +796,30 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
 static void __devexit cx8802_remove(struct pci_dev *pci_dev)
 {
        struct cx8802_dev *dev;
-       struct cx8802_driver *h;
-       struct list_head *list;
 
        dev = pci_get_drvdata(pci_dev);
 
        dprintk( 1, "%s\n", __FUNCTION__);
 
-       list_for_each(list,&dev->drvlist.devlist) {
-               h = list_entry(list, struct cx8802_driver, devlist);
-               dprintk( 1, " ->driver\n");
-               if (h->remove == NULL) {
-                       printk(KERN_ERR "%s .. skipping driver, no probe function\n", __FUNCTION__);
-                       continue;
+       if (!list_empty(&dev->drvlist)) {
+               struct cx8802_driver *drv, *tmp;
+               int err;
+
+               printk(KERN_WARNING "%s/2: Trying to remove cx8802 driver "
+                      "while cx8802 sub-drivers still loaded?!\n",
+                      dev->core->name);
+
+               list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) {
+                       err = drv->remove(drv);
+                       if (err == 0) {
+                               mutex_lock(&drv->core->lock);
+                               list_del(&drv->drvlist);
+                               mutex_unlock(&drv->core->lock);
+                       } else
+                               printk(KERN_ERR "%s/2: cx8802 driver remove "
+                                      "failed (%d)\n", dev->core->name, err);
+                       kfree(drv);
                }
-               printk(KERN_INFO "%s .. Removing driver type %d\n", __FUNCTION__, h->type_id);
-               cx8802_unregister_driver(h);
-               list_del(&dev->drvlist.devlist);
        }
 
        /* Destroy any 8802 reference. */
@@ -901,7 +879,6 @@ EXPORT_SYMBOL(cx8802_fini_common);
 
 EXPORT_SYMBOL(cx8802_register_driver);
 EXPORT_SYMBOL(cx8802_unregister_driver);
-EXPORT_SYMBOL(cx8802_get_device);
 EXPORT_SYMBOL(cx8802_get_driver);
 /* ----------------------------------------------------------- */
 /*
index 231ae6c..5ee05f8 100644 (file)
@@ -1675,7 +1675,6 @@ static struct video_device cx8800_radio_template =
 {
        .name                 = "cx8800-radio",
        .type                 = VID_TYPE_TUNER,
-       .hardware             = 0,
        .fops                 = &radio_fops,
        .minor                = -1,
        .vidioc_querycap      = radio_querycap,
index 77c3788..6ce5af4 100644 (file)
@@ -41,7 +41,7 @@ static void vp3054_bit_setscl(void *data, int state)
 {
        struct cx8802_dev *dev = data;
        struct cx88_core *core = dev->core;
-       struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+       struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
 
        if (state) {
                vp3054_i2c->state |=  0x0001;   /* SCL high */
@@ -58,7 +58,7 @@ static void vp3054_bit_setsda(void *data, int state)
 {
        struct cx8802_dev *dev = data;
        struct cx88_core *core = dev->core;
-       struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+       struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
 
        if (state) {
                vp3054_i2c->state |=  0x0002;   /* SDA high */
@@ -113,10 +113,10 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
        if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
                return 0;
 
-       dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
-       if (dev->card_priv == NULL)
+       vp3054_i2c = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
+       if (vp3054_i2c == NULL)
                return -ENOMEM;
-       vp3054_i2c = dev->card_priv;
+       dev->vp3054 = vp3054_i2c;
 
        memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
               sizeof(vp3054_i2c->algo));
@@ -139,8 +139,8 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
        if (0 != rc) {
                printk("%s: vp3054_i2c register FAILED\n", core->name);
 
-               kfree(dev->card_priv);
-               dev->card_priv = NULL;
+               kfree(dev->vp3054);
+               dev->vp3054 = NULL;
        }
 
        return rc;
@@ -148,7 +148,7 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
 
 void vp3054_i2c_remove(struct cx8802_dev *dev)
 {
-       struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+       struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
 
        if (vp3054_i2c == NULL ||
            dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
index 42e0a9b..eb296bd 100644 (file)
@@ -412,7 +412,9 @@ struct cx8802_suspend_state {
 
 struct cx8802_driver {
        struct cx88_core *core;
-       struct list_head devlist;
+
+       /* List of drivers attached to device */
+       struct list_head drvlist;
 
        /* Type of driver and access required */
        enum cx88_board_type type_id;
@@ -453,27 +455,33 @@ struct cx8802_dev {
 
        /* for blackbird only */
        struct list_head           devlist;
+#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \
+    defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE)
        struct video_device        *mpeg_dev;
        u32                        mailbox;
        int                        width;
        int                        height;
 
+       /* mpeg params */
+       struct cx2341x_mpeg_params params;
+#endif
+
 #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
        /* for dvb only */
        struct videobuf_dvb        dvb;
+#endif
 
-       void                       *card_priv;
+#if defined(CONFIG_VIDEO_CX88_VP3054) || \
+    defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+       /* For VP3045 secondary I2C bus support */
+       struct vp3054_i2c_state    *vp3054;
 #endif
        /* for switching modulation types */
        unsigned char              ts_gen_cntrl;
 
-       /* mpeg params */
-       struct cx2341x_mpeg_params params;
-
        /* List of attached drivers */
-       struct cx8802_driver       drvlist;
-       struct work_struct request_module_wk;
-
+       struct list_head           drvlist;
+       struct work_struct         request_module_wk;
 };
 
 /* ----------------------------------------------------------- */
index d3282ec..d56484f 100644 (file)
@@ -648,7 +648,7 @@ void em28xx_uninit_isoc(struct em28xx *dev)
  */
 int em28xx_init_isoc(struct em28xx *dev)
 {
-       /* change interface to 3 which allowes the biggest packet sizes */
+       /* change interface to 3 which allows the biggest packet sizes */
        int i, errCode;
        const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
 
@@ -673,6 +673,7 @@ int em28xx_init_isoc(struct em28xx *dev)
                                        ("unable to allocate %i bytes for transfer buffer %i\n",
                                         sb_size, i);
                        em28xx_uninit_isoc(dev);
+                       usb_free_urb(urb);
                        return -ENOMEM;
                }
                memset(dev->transfer_buffer[i], 0, sb_size);
index e467682..a4c2a90 100644 (file)
@@ -1617,7 +1617,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 
        /* Fills VBI device info */
        dev->vbi_dev->type = VFL_TYPE_VBI;
-       dev->vbi_dev->hardware = 0;
        dev->vbi_dev->fops = &em28xx_v4l_fops;
        dev->vbi_dev->minor = -1;
        dev->vbi_dev->dev = &dev->udev->dev;
@@ -1629,7 +1628,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        dev->vdev->type = VID_TYPE_CAPTURE;
        if (dev->has_tuner)
                dev->vdev->type |= VID_TYPE_TUNER;
-       dev->vdev->hardware = 0;
        dev->vdev->fops = &em28xx_v4l_fops;
        dev->vdev->minor = -1;
        dev->vdev->dev = &dev->udev->dev;
index d5fef4c..d19d73b 100644 (file)
@@ -2585,7 +2585,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");
        cam->v4ldev->owner = THIS_MODULE;
        cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = 0;
        cam->v4ldev->fops = &et61x251_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
index d98dd0d..29779d8 100644 (file)
@@ -528,6 +528,7 @@ static int ir_probe(struct i2c_adapter *adap)
                break;
        case I2C_HW_B_CX2388x:
                probe = probe_cx88;
+               break;
        case I2C_HW_B_CX23885:
                probe = probe_cx23885;
                break;
index fd7a932..6d2dd87 100644 (file)
@@ -1003,8 +1003,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 
        IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
 
-       mutex_lock(&itv->serialize_lock);
-
        /* PCI Device Setup */
        if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) {
                if (retval == -EIO)
@@ -1064,7 +1062,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        IVTV_DEBUG_INFO("activating i2c...\n");
        if (init_ivtv_i2c(itv)) {
                IVTV_ERR("Could not initialize i2c\n");
-               goto free_irq;
+               goto free_io;
        }
 
        IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
@@ -1176,7 +1174,11 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                IVTV_ERR("Failed to register irq %d\n", retval);
                goto free_streams;
        }
-       mutex_unlock(&itv->serialize_lock);
+       retval = ivtv_streams_register(itv);
+       if (retval) {
+               IVTV_ERR("Error %d registering devices\n", retval);
+               goto free_irq;
+       }
        IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
        return 0;
 
@@ -1195,7 +1197,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
       free_workqueue:
        destroy_workqueue(itv->irq_work_queues);
-       mutex_unlock(&itv->serialize_lock);
       err:
        if (retval == 0)
                retval = -ENODEV;
index 3bda1df..49ce14d 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/unistd.h>
 #include <linux/byteorder/swab.h>
 #include <linux/pagemap.h>
+#include <linux/scatterlist.h>
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
index da50fa4..a200a8a 100644 (file)
@@ -822,6 +822,11 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
                        crystal_freq.flags = 0;
                        ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
                }
+               if (atomic_read(&itv->capturing) > 0) {
+                       /* Undo video mute */
+                       ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
+                               itv->params.video_mute | (itv->params.video_mute_yuv << 8));
+               }
                /* Done! Unmute and continue. */
                ivtv_unmute(itv);
                ivtv_release_stream(s);
@@ -892,6 +897,7 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
                        if (atomic_read(&itv->capturing) > 0) {
                                /* switching to radio while capture is
                                   in progress is not polite */
+                               ivtv_release_stream(s);
                                kfree(item);
                                return -EBUSY;
                        }
@@ -947,7 +953,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
        if (itv == NULL) {
                /* Couldn't find a device registered
                   on that minor, shouldn't happen! */
-               IVTV_WARN("No ivtv device found on minor %d\n", minor);
+               printk(KERN_WARNING "No ivtv device found on minor %d\n", minor);
                return -ENXIO;
        }
 
index 206eee7..fd6826f 100644 (file)
@@ -555,6 +555,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
 
        /* set window size */
        if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               struct cx2341x_mpeg_params *p = &itv->params;
                int w = fmt->fmt.pix.width;
                int h = fmt->fmt.pix.height;
 
@@ -566,17 +567,19 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
                fmt->fmt.pix.width = w;
                fmt->fmt.pix.height = h;
 
-               if (!set_fmt || (itv->params.width == w && itv->params.height == h))
+               if (!set_fmt || (p->width == w && p->height == h))
                        return 0;
                if (atomic_read(&itv->capturing) > 0)
                        return -EBUSY;
 
-               itv->params.width = w;
-               itv->params.height = h;
+               p->width = w;
+               p->height = h;
                if (w != 720 || h != (itv->is_50hz ? 576 : 480))
-                       itv->params.video_temporal_filter = 0;
+                       p->video_temporal_filter = 0;
                else
-                       itv->params.video_temporal_filter = 8;
+                       p->video_temporal_filter = 8;
+               if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+                       fmt->fmt.pix.width /= 2;
                itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
                return ivtv_get_fmt(itv, streamtype, fmt);
        }
index fd13598..aa03e61 100644 (file)
@@ -166,10 +166,9 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
        ivtv_queue_init(&s->q_io);
 }
 
-static int ivtv_reg_dev(struct ivtv *itv, int type)
+static int ivtv_prep_dev(struct ivtv *itv, int type)
 {
        struct ivtv_stream *s = &itv->streams[type];
-       int vfl_type = ivtv_stream_info[type].vfl_type;
        int minor_offset = ivtv_stream_info[type].minor_offset;
        int minor;
 
@@ -187,15 +186,12 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
        if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                return 0;
 
-       if (minor_offset >= 0)
-               /* card number + user defined offset + device offset */
-               minor = itv->num + ivtv_first_minor + minor_offset;
-       else
-               minor = -1;
+       /* card number + user defined offset + device offset */
+       minor = itv->num + ivtv_first_minor + minor_offset;
 
        /* User explicitly selected 0 buffers for these streams, so don't
           create them. */
-       if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE &&
+       if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&
            itv->options.kilobytes[type] == 0) {
                IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
                return 0;
@@ -223,21 +219,53 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
        s->v4l2dev->fops = ivtv_stream_info[type].fops;
        s->v4l2dev->release = video_device_release;
 
-       if (minor >= 0) {
-               /* Register device. First try the desired minor, then any free one. */
-               if (video_register_device(s->v4l2dev, vfl_type, minor) &&
-                   video_register_device(s->v4l2dev, vfl_type, -1)) {
-                       IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n",
-                                       s->name, minor);
-                       video_device_release(s->v4l2dev);
-                       s->v4l2dev = NULL;
-                       return -ENOMEM;
-               }
+       return 0;
+}
+
+/* Initialize v4l2 variables and prepare v4l2 devices */
+int ivtv_streams_setup(struct ivtv *itv)
+{
+       int type;
+
+       /* Setup V4L2 Devices */
+       for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+               /* Prepare device */
+               if (ivtv_prep_dev(itv, type))
+                       break;
+
+               if (itv->streams[type].v4l2dev == NULL)
+                       continue;
+
+               /* Allocate Stream */
+               if (ivtv_stream_alloc(&itv->streams[type]))
+                       break;
        }
-       else {
-               /* Don't register a 'hidden' stream (OSD) */
-               IVTV_INFO("Created framebuffer stream for %s\n", s->name);
+       if (type == IVTV_MAX_STREAMS)
                return 0;
+
+       /* One or more streams could not be initialized. Clean 'em all up. */
+       ivtv_streams_cleanup(itv);
+       return -ENOMEM;
+}
+
+static int ivtv_reg_dev(struct ivtv *itv, int type)
+{
+       struct ivtv_stream *s = &itv->streams[type];
+       int vfl_type = ivtv_stream_info[type].vfl_type;
+       int minor;
+
+       if (s->v4l2dev == NULL)
+               return 0;
+
+       minor = s->v4l2dev->minor;
+       /* Register device. First try the desired minor, then any free one. */
+       if (video_register_device(s->v4l2dev, vfl_type, minor) &&
+                       video_register_device(s->v4l2dev, vfl_type, -1)) {
+               IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n",
+                               s->name, minor);
+               video_device_release(s->v4l2dev);
+               s->v4l2dev = NULL;
+               return -ENOMEM;
        }
 
        switch (vfl_type) {
@@ -262,27 +290,18 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
        return 0;
 }
 
-/* Initialize v4l2 variables and register v4l2 devices */
-int ivtv_streams_setup(struct ivtv *itv)
+/* Register v4l2 devices */
+int ivtv_streams_register(struct ivtv *itv)
 {
        int type;
+       int err = 0;
 
-       /* Setup V4L2 Devices */
-       for (type = 0; type < IVTV_MAX_STREAMS; type++) {
-               /* Register Device */
-               if (ivtv_reg_dev(itv, type))
-                       break;
-
-               if (itv->streams[type].v4l2dev == NULL)
-                       continue;
+       /* Register V4L2 devices */
+       for (type = 0; type < IVTV_MAX_STREAMS; type++)
+               err |= ivtv_reg_dev(itv, type);
 
-               /* Allocate Stream */
-               if (ivtv_stream_alloc(&itv->streams[type]))
-                       break;
-       }
-       if (type == IVTV_MAX_STREAMS) {
+       if (err == 0)
                return 0;
-       }
 
        /* One or more streams could not be initialized. Clean 'em all up. */
        ivtv_streams_cleanup(itv);
@@ -303,11 +322,8 @@ void ivtv_streams_cleanup(struct ivtv *itv)
                        continue;
 
                ivtv_stream_free(&itv->streams[type]);
-               /* Free Device */
-               if (vdev->minor == -1) /* 'Hidden' never registered stream (OSD) */
-                       video_device_release(vdev);
-               else    /* All others, just unregister. */
-                       video_unregister_device(vdev);
+               /* Unregister device */
+               video_unregister_device(vdev);
        }
 }
 
@@ -425,6 +441,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
 {
        u32 data[CX2341X_MBOX_MAX_DATA];
        struct ivtv *itv = s->itv;
+       struct cx2341x_mpeg_params *p = &itv->params;
        int captype = 0, subtype = 0;
        int enable_passthrough = 0;
 
@@ -445,7 +462,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                }
                itv->mpg_data_received = itv->vbi_data_inserted = 0;
                itv->dualwatch_jiffies = jiffies;
-               itv->dualwatch_stereo_mode = itv->params.audio_properties & 0x0300;
+               itv->dualwatch_stereo_mode = p->audio_properties & 0x0300;
                itv->search_pack_header = 0;
                break;
 
@@ -477,9 +494,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
        s->subtype = subtype;
        s->buffers_stolen = 0;
 
-       /* mute/unmute video */
-       ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? 1 : 0);
-
        /* Clear Streamoff flags in case left from last capture */
        clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
 
@@ -536,7 +550,12 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                                itv->pgm_info_offset, itv->pgm_info_num);
 
                /* Setup API for Stream */
-               cx2341x_update(itv, ivtv_api_func, NULL, &itv->params);
+               cx2341x_update(itv, ivtv_api_func, NULL, p);
+
+               /* mute if capturing radio */
+               if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
+                       ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
+                               1 | (p->video_mute_yuv << 8));
        }
 
        /* Vsync Setup */
@@ -585,6 +604,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
 {
        u32 data[CX2341X_MBOX_MAX_DATA];
        struct ivtv *itv = s->itv;
+       struct cx2341x_mpeg_params *p = &itv->params;
        int datatype;
 
        if (s->v4l2dev == NULL)
@@ -623,7 +643,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
                break;
        }
        if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
-                       itv->params.width, itv->params.height, itv->params.audio_properties)) {
+                       p->width, p->height, p->audio_properties)) {
                IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
        }
        return 0;
index 8f5f5b1..3d76a41 100644 (file)
@@ -22,6 +22,7 @@
 #define IVTV_STREAMS_H
 
 int ivtv_streams_setup(struct ivtv *itv);
+int ivtv_streams_register(struct ivtv *itv);
 void ivtv_streams_cleanup(struct ivtv *itv);
 
 /* Capture related */
index c4626d1..912b424 100644 (file)
@@ -63,10 +63,10 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info
                        memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len);
                        kunmap_atomic(src, KM_BOUNCE_READ);
                        local_irq_restore(flags);
-                       dma->SGlist[map_offset].page = dma->bouncemap[map_offset];
+                       sg_set_page(&dma->SGlist[map_offset], dma->bouncemap[map_offset]);
                }
                else {
-                       dma->SGlist[map_offset].page = dma->map[map_offset];
+                       sg_set_page(&dma->SGlist[map_offset], dma->map[map_offset]);
                }
                offset = 0;
                map_offset++;
index e2288f2..9091c48 100644 (file)
@@ -710,7 +710,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
 
        /* If there's nothing to safe to display, we may as well stop now */
        if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
-               return 0;
+               return IVTV_YUV_UPDATE_INVALID;
        }
 
        /* Ensure video remains inside OSD area */
@@ -791,7 +791,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
 
        /* Check again. If there's nothing to safe to display, stop now */
        if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
-               return 0;
+               return IVTV_YUV_UPDATE_INVALID;
        }
 
        /* Both x offset & width are linked, so they have to be done together */
@@ -840,110 +840,118 @@ void ivtv_yuv_work_handler (struct ivtv *itv)
        if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
                return;
 
-       /* Update horizontal settings */
-       if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
-               ivtv_yuv_handle_horizontal(itv, &window);
+       if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
+               write_reg(0x01008080, 0x2898);
+       } else if (yuv_update) {
+               write_reg(0x00108080, 0x2898);
 
-       if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
-               ivtv_yuv_handle_vertical(itv, &window);
+               if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
+                       ivtv_yuv_handle_horizontal(itv, &window);
+
+               if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
+                       ivtv_yuv_handle_vertical(itv, &window);
+       }
 
        memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
 }
 
 static void ivtv_yuv_init (struct ivtv *itv)
 {
+       struct yuv_playback_info *yi = &itv->yuv_info;
+
        IVTV_DEBUG_YUV("ivtv_yuv_init\n");
 
        /* Take a snapshot of the current register settings */
-       itv->yuv_info.reg_2834 = read_reg(0x02834);
-       itv->yuv_info.reg_2838 = read_reg(0x02838);
-       itv->yuv_info.reg_283c = read_reg(0x0283c);
-       itv->yuv_info.reg_2840 = read_reg(0x02840);
-       itv->yuv_info.reg_2844 = read_reg(0x02844);
-       itv->yuv_info.reg_2848 = read_reg(0x02848);
-       itv->yuv_info.reg_2854 = read_reg(0x02854);
-       itv->yuv_info.reg_285c = read_reg(0x0285c);
-       itv->yuv_info.reg_2864 = read_reg(0x02864);
-       itv->yuv_info.reg_2870 = read_reg(0x02870);
-       itv->yuv_info.reg_2874 = read_reg(0x02874);
-       itv->yuv_info.reg_2898 = read_reg(0x02898);
-       itv->yuv_info.reg_2890 = read_reg(0x02890);
-
-       itv->yuv_info.reg_289c = read_reg(0x0289c);
-       itv->yuv_info.reg_2918 = read_reg(0x02918);
-       itv->yuv_info.reg_291c = read_reg(0x0291c);
-       itv->yuv_info.reg_2920 = read_reg(0x02920);
-       itv->yuv_info.reg_2924 = read_reg(0x02924);
-       itv->yuv_info.reg_2928 = read_reg(0x02928);
-       itv->yuv_info.reg_292c = read_reg(0x0292c);
-       itv->yuv_info.reg_2930 = read_reg(0x02930);
-       itv->yuv_info.reg_2934 = read_reg(0x02934);
-       itv->yuv_info.reg_2938 = read_reg(0x02938);
-       itv->yuv_info.reg_293c = read_reg(0x0293c);
-       itv->yuv_info.reg_2940 = read_reg(0x02940);
-       itv->yuv_info.reg_2944 = read_reg(0x02944);
-       itv->yuv_info.reg_2948 = read_reg(0x02948);
-       itv->yuv_info.reg_294c = read_reg(0x0294c);
-       itv->yuv_info.reg_2950 = read_reg(0x02950);
-       itv->yuv_info.reg_2954 = read_reg(0x02954);
-       itv->yuv_info.reg_2958 = read_reg(0x02958);
-       itv->yuv_info.reg_295c = read_reg(0x0295c);
-       itv->yuv_info.reg_2960 = read_reg(0x02960);
-       itv->yuv_info.reg_2964 = read_reg(0x02964);
-       itv->yuv_info.reg_2968 = read_reg(0x02968);
-       itv->yuv_info.reg_296c = read_reg(0x0296c);
-       itv->yuv_info.reg_2970 = read_reg(0x02970);
-
-       itv->yuv_info.v_filter_1 = -1;
-       itv->yuv_info.v_filter_2 = -1;
-       itv->yuv_info.h_filter = -1;
+       yi->reg_2834 = read_reg(0x02834);
+       yi->reg_2838 = read_reg(0x02838);
+       yi->reg_283c = read_reg(0x0283c);
+       yi->reg_2840 = read_reg(0x02840);
+       yi->reg_2844 = read_reg(0x02844);
+       yi->reg_2848 = read_reg(0x02848);
+       yi->reg_2854 = read_reg(0x02854);
+       yi->reg_285c = read_reg(0x0285c);
+       yi->reg_2864 = read_reg(0x02864);
+       yi->reg_2870 = read_reg(0x02870);
+       yi->reg_2874 = read_reg(0x02874);
+       yi->reg_2898 = read_reg(0x02898);
+       yi->reg_2890 = read_reg(0x02890);
+
+       yi->reg_289c = read_reg(0x0289c);
+       yi->reg_2918 = read_reg(0x02918);
+       yi->reg_291c = read_reg(0x0291c);
+       yi->reg_2920 = read_reg(0x02920);
+       yi->reg_2924 = read_reg(0x02924);
+       yi->reg_2928 = read_reg(0x02928);
+       yi->reg_292c = read_reg(0x0292c);
+       yi->reg_2930 = read_reg(0x02930);
+       yi->reg_2934 = read_reg(0x02934);
+       yi->reg_2938 = read_reg(0x02938);
+       yi->reg_293c = read_reg(0x0293c);
+       yi->reg_2940 = read_reg(0x02940);
+       yi->reg_2944 = read_reg(0x02944);
+       yi->reg_2948 = read_reg(0x02948);
+       yi->reg_294c = read_reg(0x0294c);
+       yi->reg_2950 = read_reg(0x02950);
+       yi->reg_2954 = read_reg(0x02954);
+       yi->reg_2958 = read_reg(0x02958);
+       yi->reg_295c = read_reg(0x0295c);
+       yi->reg_2960 = read_reg(0x02960);
+       yi->reg_2964 = read_reg(0x02964);
+       yi->reg_2968 = read_reg(0x02968);
+       yi->reg_296c = read_reg(0x0296c);
+       yi->reg_2970 = read_reg(0x02970);
+
+       yi->v_filter_1 = -1;
+       yi->v_filter_2 = -1;
+       yi->h_filter = -1;
 
        /* Set some valid size info */
-       itv->yuv_info.osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
-       itv->yuv_info.osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
+       yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
+       yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
 
        /* Bit 2 of reg 2878 indicates current decoder output format
           0 : NTSC    1 : PAL */
        if (read_reg(0x2878) & 4)
-               itv->yuv_info.decode_height = 576;
+               yi->decode_height = 576;
        else
-               itv->yuv_info.decode_height = 480;
+               yi->decode_height = 480;
 
-       /* If no visible size set, assume full size */
-       if (!itv->yuv_info.osd_vis_w)
-               itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
-
-       if (!itv->yuv_info.osd_vis_h) {
-               itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+       if (!itv->osd_info) {
+               yi->osd_vis_w = 720 - yi->osd_x_offset;
+               yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
        } else {
-               /* If output video standard has changed, requested height may
-               not be legal */
-               if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) {
-                       IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
-                                       itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset,
-                                       itv->yuv_info.decode_height);
-                       itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+               /* If no visible size set, assume full size */
+               if (!yi->osd_vis_w)
+                       yi->osd_vis_w = 720 - yi->osd_x_offset;
+
+               if (!yi->osd_vis_h)
+                       yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+               else {
+                       /* If output video standard has changed, requested height may
+                       not be legal */
+                       if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
+                               IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
+                                               yi->osd_vis_h + yi->osd_y_offset,
+                                               yi->decode_height);
+                               yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+                       }
                }
        }
 
        /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
-       itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL);
-       if (itv->yuv_info.blanking_ptr) {
-               itv->yuv_info.blanking_dmaptr = pci_map_single(itv->dev, itv->yuv_info.blanking_ptr, 720*16, PCI_DMA_TODEVICE);
-       }
+       yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL);
+       if (yi->blanking_ptr)
+               yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
        else {
-               itv->yuv_info.blanking_dmaptr = 0;
-               IVTV_DEBUG_WARN ("Failed to allocate yuv blanking buffer\n");
+               yi->blanking_dmaptr = 0;
+               IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
        }
 
-       IVTV_DEBUG_WARN("Enable video output\n");
-       write_reg_sync(0x00108080, 0x2898);
-
        /* Enable YUV decoder output */
        write_reg_sync(0x01, IVTV_REG_VDM);
 
        set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
-       atomic_set(&itv->yuv_info.next_dma_frame,0);
+       atomic_set(&yi->next_dma_frame, 0);
 }
 
 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
index f7215ee..3b966f0 100644 (file)
@@ -34,6 +34,7 @@
 
 #define IVTV_YUV_UPDATE_HORIZONTAL  0x01
 #define IVTV_YUV_UPDATE_VERTICAL    0x02
+#define IVTV_YUV_UPDATE_INVALID     0x04
 
 extern const u32 yuv_offset[4];
 
index 9684048..52ffd15 100644 (file)
@@ -55,7 +55,6 @@
 static int ivtvfb_card_id = -1;
 static int ivtvfb_debug = 0;
 static int osd_laced;
-static int osd_compat;
 static int osd_depth;
 static int osd_upper;
 static int osd_left;
@@ -65,7 +64,6 @@ static int osd_xres;
 module_param(ivtvfb_card_id, int, 0444);
 module_param_named(debug,ivtvfb_debug, int, 0644);
 module_param(osd_laced, bool, 0444);
-module_param(osd_compat, bool, 0444);
 module_param(osd_depth, int, 0444);
 module_param(osd_upper, int, 0444);
 module_param(osd_left, int, 0444);
@@ -80,12 +78,6 @@ MODULE_PARM_DESC(debug,
                 "Debug level (bitmask). Default: errors only\n"
                 "\t\t\t(debug = 3 gives full debugging)");
 
-MODULE_PARM_DESC(osd_compat,
-                "Compatibility mode - Display size is locked (use for old X drivers)\n"
-                "\t\t\t0=off\n"
-                "\t\t\t1=on\n"
-                "\t\t\tdefault off");
-
 /* Why upper, left, xres, yres, depth, laced ? To match terminology used
    by fbset.
    Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
@@ -166,9 +158,6 @@ struct osd_info {
        unsigned long fb_end_aligned_physaddr;
 #endif
 
-       /* Current osd mode */
-       int osd_mode;
-
        /* Store the buffer offset */
        int set_osd_coords_x;
        int set_osd_coords_y;
@@ -470,13 +459,11 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
                        IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
        }
 
-       /* Change osd mode if needed.
-          Although rare, things can go wrong. The extra mode
-          change seems to help... */
-       if (osd_mode != -1 && osd_mode != oi->osd_mode) {
+       /* Set video mode. Although rare, the display can become scrambled even
+          if we don't change mode. Always 'bounce' to osd_mode via mode 0 */
+       if (osd_mode != -1) {
                ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
                ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
-               oi->osd_mode = osd_mode;
        }
 
        oi->bits_per_pixel = var->bits_per_pixel;
@@ -579,14 +566,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
                osd_height_limit = 480;
        }
 
-       /* Check the bits per pixel */
-       if (osd_compat) {
-               if (var->bits_per_pixel != 32) {
-                       IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
-                       return -EINVAL;
-               }
-       }
-
        if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
                var->transp.offset = 24;
                var->transp.length = 8;
@@ -638,32 +617,20 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
        }
 
        /* Check the resolution */
-       if (osd_compat) {
-               if (var->xres != oi->ivtvfb_defined.xres ||
-                   var->yres != oi->ivtvfb_defined.yres ||
-                   var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
-                   var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
-                       IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
-                               var->xres, var->yres, var->xres_virtual, var->yres_virtual);
-                       return -EINVAL;
-               }
+       if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
+               IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
+                               var->xres, var->yres);
+               return -EINVAL;
        }
-       else {
-               if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
-                       IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
-                                       var->xres, var->yres);
-                       return -EINVAL;
-               }
 
-               /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
-               if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
-                   var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
-                   var->xres_virtual < var->xres ||
-                   var->yres_virtual < var->yres) {
-                       IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
-                               var->xres_virtual, var->yres_virtual);
-                       return -EINVAL;
-               }
+       /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
+       if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
+           var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
+           var->xres_virtual < var->xres ||
+           var->yres_virtual < var->yres) {
+               IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
+                       var->xres_virtual, var->yres_virtual);
+               return -EINVAL;
        }
 
        /* Some extra checks if in 8 bit mode */
@@ -877,17 +844,15 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
 
        /* Color mode */
 
-       if (osd_compat) osd_depth = 32;
-       if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
+       if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32)
+               osd_depth = 8;
        oi->bits_per_pixel = osd_depth;
        oi->bytes_per_pixel = oi->bits_per_pixel / 8;
 
-       /* Invalidate current osd mode to force a mode switch later */
-       oi->osd_mode = -1;
-
        /* Horizontal size & position */
 
-       if (osd_xres > 720) osd_xres = 720;
+       if (osd_xres > 720)
+               osd_xres = 720;
 
        /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
        if (osd_depth == 8)
@@ -895,10 +860,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
        else if (osd_depth == 16)
                osd_xres &= ~1;
 
-       if (osd_xres)
-               start_window.width = osd_xres;
-       else
-               start_window.width = osd_compat ? 720: 640;
+       start_window.width = osd_xres ? osd_xres : 640;
 
        /* Check horizontal start (osd_left). */
        if (osd_left && osd_left + start_window.width > 721) {
@@ -921,10 +883,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
        if (osd_yres > max_height)
                osd_yres = max_height;
 
-       if (osd_yres)
-               start_window.height = osd_yres;
-       else
-               start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
+       start_window.height = osd_yres ? osd_yres : itv->is_50hz ? 480 : 400;
 
        /* Check vertical start (osd_upper). */
        if (osd_upper + start_window.height > max_height + 1) {
@@ -1127,10 +1086,6 @@ static int ivtvfb_init_card(struct ivtv *itv)
        /* Enable the osd */
        ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
 
-       /* Note if we're running in compatibility mode */
-       if (osd_compat)
-               IVTVFB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
-
        /* Allocate DMA */
        ivtv_udma_alloc(itv);
        return 0;
@@ -1177,9 +1132,12 @@ static void ivtvfb_cleanup(void)
        for (i = 0; i < ivtv_cards_active; i++) {
                itv = ivtv_cards[i];
                if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
+                       if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
+                               IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", i);
+                               return;
+                       }
                        IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i);
                        ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
-                       unregister_framebuffer(&itv->osd_info->ivtvfb_info);
                        ivtvfb_release_buffers(itv);
                        itv->osd_video_pbase = 0;
                }
index 6928392..c311632 100644 (file)
@@ -1762,7 +1762,6 @@ static struct video_device meye_template = {
        .owner          = THIS_MODULE,
        .name           = "meye",
        .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_MEYE,
        .fops           = &meye_fops,
        .release        = video_device_release,
        .minor          = -1,
index b8d4ac0..d55d580 100644 (file)
@@ -4668,7 +4668,6 @@ static struct video_device vdev_template = {
        .owner =        THIS_MODULE,
        .name =         "OV511 USB Camera",
        .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_OV511,
        .fops =         &ov511_fops,
        .release =      video_device_release,
        .minor =        -1,
index 0ef73d9..ce4b2f9 100644 (file)
@@ -2013,7 +2013,6 @@ static struct video_device planb_template=
        .owner          = THIS_MODULE,
        .name           = PLANB_DEVICE_NAME,
        .type           = VID_TYPE_OVERLAY,
-       .hardware       = VID_HARDWARE_PLANB,
        .open           = planb_open,
        .close          = planb_close,
        .read           = planb_read,
index b5a67f0..6820c2a 100644 (file)
@@ -895,7 +895,6 @@ static struct video_device pms_template=
        .owner          = THIS_MODULE,
        .name           = "Mediavision PMS",
        .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_PMS,
        .fops           = &pms_fops,
 };
 
index 20b6144..205087a 100644 (file)
@@ -209,6 +209,11 @@ static int pvr2_encoder_cmd(void *ctxt,
 
        LOCK_TAKE(hdw->ctl_lock); do {
 
+               if (!hdw->flag_encoder_ok) {
+                       ret = -EIO;
+                       break;
+               }
+
                retry_flag = 0;
                try_count++;
                ret = 0;
@@ -273,6 +278,7 @@ static int pvr2_encoder_cmd(void *ctxt,
                        ret = -EBUSY;
                }
                if (ret) {
+                       hdw->flag_encoder_ok = 0;
                        pvr2_trace(
                                PVR2_TRACE_ERROR_LEGS,
                                "Giving up on command."
index 985d9ae..f873994 100644 (file)
@@ -225,11 +225,12 @@ struct pvr2_hdw {
        unsigned int cmd_debug_write_len;  //
        unsigned int cmd_debug_read_len;   //
 
-       int flag_ok;            // device in known good state
-       int flag_disconnected;  // flag_ok == 0 due to disconnect
-       int flag_init_ok;       // true if structure is fully initialized
-       int flag_streaming_enabled; // true if streaming should be on
-       int fw1_state;          // current situation with fw1
+       int flag_ok;            /* device in known good state */
+       int flag_disconnected;  /* flag_ok == 0 due to disconnect */
+       int flag_init_ok;       /* true if structure is fully initialized */
+       int flag_streaming_enabled; /* true if streaming should be on */
+       int fw1_state;          /* current situation with fw1 */
+       int flag_encoder_ok;    /* True if encoder is healthy */
 
        int flag_decoder_is_tuned;
 
index 27b12b4..402c594 100644 (file)
@@ -1248,6 +1248,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
           time we configure the encoder, then we'll fully configure it. */
        hdw->enc_cur_valid = 0;
 
+       hdw->flag_encoder_ok = 0;
+
        /* First prepare firmware loading */
        ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
        ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
@@ -1346,6 +1348,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "firmware2 upload post-proc failure");
        } else {
+               hdw->flag_encoder_ok = !0;
                hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
        }
        return ret;
index 4563b3d..7a596ea 100644 (file)
@@ -1121,15 +1121,12 @@ static const struct file_operations vdev_fops = {
 };
 
 
-#define VID_HARDWARE_PVRUSB2    38  /* FIXME : need a good value */
-
 static struct video_device vdev_template = {
        .owner      = THIS_MODULE,
        .type       = VID_TYPE_CAPTURE | VID_TYPE_TUNER,
        .type2      = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE
                       | V4L2_CAP_TUNER | V4L2_CAP_AUDIO
                       | V4L2_CAP_READWRITE),
-       .hardware   = VID_HARDWARE_PVRUSB2,
        .fops       = &vdev_fops,
 };
 
index 950da25..7300ace 100644 (file)
@@ -166,7 +166,6 @@ static struct video_device pwc_template = {
        .owner =        THIS_MODULE,
        .name =         "Philips Webcam",       /* Filled in later */
        .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_PWC,
        .release =      video_device_release,
        .fops =         &pwc_fops,
        .minor =        -1,
index 57f1f5d..002e70a 100644 (file)
@@ -71,7 +71,6 @@ static const struct v4l2_format v4l2_format_table[] =
 
 struct saa6752hs_state {
        struct i2c_client             client;
-       struct v4l2_mpeg_compression  old_params;
        struct saa6752hs_mpeg_params  params;
        enum saa6752hs_videoformat    video_format;
        v4l2_std_id                   standard;
@@ -161,35 +160,6 @@ static struct saa6752hs_mpeg_params param_defaults =
        .au_l2_bitrate   = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
 };
 
-static struct v4l2_mpeg_compression old_param_defaults =
-{
-       .st_type         = V4L2_MPEG_TS_2,
-       .st_bitrate      = {
-               .mode    = V4L2_BITRATE_CBR,
-               .target  = 7000,
-       },
-
-       .ts_pid_pmt      = 16,
-       .ts_pid_video    = 260,
-       .ts_pid_audio    = 256,
-       .ts_pid_pcr      = 259,
-
-       .vi_type         = V4L2_MPEG_VI_2,
-       .vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
-       .vi_bitrate      = {
-               .mode    = V4L2_BITRATE_VBR,
-               .target  = 4000,
-               .max     = 6000,
-       },
-
-       .au_type         = V4L2_MPEG_AU_2_II,
-       .au_bitrate      = {
-               .mode    = V4L2_BITRATE_CBR,
-               .target  = 256,
-       },
-
-};
-
 /* ---------------------------------------------------------------------- */
 
 static int saa6752hs_chip_command(struct i2c_client* client,
@@ -362,74 +332,6 @@ static void saa6752hs_set_subsampling(struct i2c_client* client,
 }
 
 
-static void saa6752hs_old_set_params(struct i2c_client* client,
-                                struct v4l2_mpeg_compression* params)
-{
-       struct saa6752hs_state *h = i2c_get_clientdata(client);
-
-       /* check PIDs */
-       if (params->ts_pid_pmt <= MPEG_PID_MAX) {
-               h->old_params.ts_pid_pmt = params->ts_pid_pmt;
-               h->params.ts_pid_pmt = params->ts_pid_pmt;
-       }
-       if (params->ts_pid_pcr <= MPEG_PID_MAX) {
-               h->old_params.ts_pid_pcr = params->ts_pid_pcr;
-               h->params.ts_pid_pcr = params->ts_pid_pcr;
-       }
-       if (params->ts_pid_video <= MPEG_PID_MAX) {
-               h->old_params.ts_pid_video = params->ts_pid_video;
-               h->params.ts_pid_video = params->ts_pid_video;
-       }
-       if (params->ts_pid_audio <= MPEG_PID_MAX) {
-               h->old_params.ts_pid_audio = params->ts_pid_audio;
-               h->params.ts_pid_audio = params->ts_pid_audio;
-       }
-
-       /* check bitrate parameters */
-       if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
-           (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) {
-               h->old_params.vi_bitrate.mode = params->vi_bitrate.mode;
-               h->params.vi_bitrate_mode = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ?
-                      V4L2_MPEG_VIDEO_BITRATE_MODE_VBR : V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
-       }
-       if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
-               h->old_params.st_bitrate.target = params->st_bitrate.target;
-       if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
-               h->old_params.vi_bitrate.target = params->vi_bitrate.target;
-       if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
-               h->old_params.vi_bitrate.max = params->vi_bitrate.max;
-       if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
-               h->old_params.au_bitrate.target = params->au_bitrate.target;
-
-       /* aspect ratio */
-       if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
-           params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) {
-               h->old_params.vi_aspect_ratio = params->vi_aspect_ratio;
-               if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3)
-                       h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
-               else
-                       h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_16x9;
-       }
-
-       /* range checks */
-       if (h->old_params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
-               h->old_params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
-       if (h->old_params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
-               h->old_params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
-       if (h->old_params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
-               h->old_params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
-       h->params.vi_bitrate = params->vi_bitrate.target;
-       h->params.vi_bitrate_peak = params->vi_bitrate.max;
-       if (h->old_params.au_bitrate.target <= 256) {
-               h->old_params.au_bitrate.target = 256;
-               h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
-       }
-       else {
-               h->old_params.au_bitrate.target = 384;
-               h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
-       }
-}
-
 static int handle_ctrl(struct saa6752hs_mpeg_params *params,
                struct v4l2_ext_control *ctrl, unsigned int cmd)
 {
@@ -697,7 +599,6 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
                return -ENOMEM;
        h->client = client_template;
        h->params = param_defaults;
-       h->old_params = old_param_defaults;
        h->client.adapter = adap;
        h->client.addr = addr;
 
@@ -734,23 +635,11 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct saa6752hs_state *h = i2c_get_clientdata(client);
        struct v4l2_ext_controls *ctrls = arg;
-       struct v4l2_mpeg_compression *old_params = arg;
        struct saa6752hs_mpeg_params params;
        int err = 0;
        int i;
 
        switch (cmd) {
-       case VIDIOC_S_MPEGCOMP:
-               if (NULL == old_params) {
-                       /* apply settings and start encoder */
-                       saa6752hs_init(client);
-                       break;
-               }
-               saa6752hs_old_set_params(client, old_params);
-               /* fall through */
-       case VIDIOC_G_MPEGCOMP:
-               *old_params = h->old_params;
-               break;
        case VIDIOC_S_EXT_CTRLS:
                if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
                        return -EINVAL;
index 1a4a244..a499eea 100644 (file)
@@ -429,7 +429,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
 
        assert_spin_locked(&dev->slock);
 
-       if (dev->inresume)
+       if (dev->insuspend)
                return 0;
 
        /* video capture -- dma 0 + video task A */
@@ -563,6 +563,9 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
        unsigned long report,status;
        int loop, handled = 0;
 
+       if (dev->insuspend)
+               goto out;
+
        for (loop = 0; loop < 10; loop++) {
                report = saa_readl(SAA7134_IRQ_REPORT);
                status = saa_readl(SAA7134_IRQ_STATUS);
@@ -1163,6 +1166,7 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
        kfree(dev);
 }
 
+#ifdef CONFIG_PM
 static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
 {
 
@@ -1176,6 +1180,19 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
        saa_writel(SAA7134_IRQ2, 0);
        saa_writel(SAA7134_MAIN_CTRL, 0);
 
+       synchronize_irq(pci_dev->irq);
+       dev->insuspend = 1;
+
+       /* Disable timeout timers - if we have active buffers, we will
+          fill them on resume*/
+
+       del_timer(&dev->video_q.timeout);
+       del_timer(&dev->vbi_q.timeout);
+       del_timer(&dev->ts_q.timeout);
+
+       if (dev->remote)
+               saa7134_ir_stop(dev);
+
        pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
        pci_save_state(pci_dev);
 
@@ -1194,24 +1211,27 @@ static int saa7134_resume(struct pci_dev *pci_dev)
        /* Do things that are done in saa7134_initdev ,
                except of initializing memory structures.*/
 
-       dev->inresume = 1;
        saa7134_board_init1(dev);
 
+       /* saa7134_hwinit1 */
        if (saa7134_boards[dev->board].video_out)
                saa7134_videoport_init(dev);
-
        if (card_has_mpeg(dev))
                saa7134_ts_init_hw(dev);
-
+       if (dev->remote)
+               saa7134_ir_start(dev, dev->remote);
        saa7134_hw_enable1(dev);
-       saa7134_set_decoder(dev);
-       saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
+
+
        saa7134_board_init2(dev);
-       saa7134_hw_enable2(dev);
 
+       /*saa7134_hwinit2*/
+       saa7134_set_tvnorm_hw(dev);
        saa7134_tvaudio_setmute(dev);
        saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
+       saa7134_tvaudio_do_scan(dev);
        saa7134_enable_i2s(dev);
+       saa7134_hw_enable2(dev);
 
        /*resume unfinished buffer(s)*/
        spin_lock_irqsave(&dev->slock, flags);
@@ -1219,13 +1239,19 @@ static int saa7134_resume(struct pci_dev *pci_dev)
        saa7134_buffer_requeue(dev, &dev->vbi_q);
        saa7134_buffer_requeue(dev, &dev->ts_q);
 
+       /* FIXME: Disable DMA audio sound - temporary till proper support
+                 is implemented*/
+
+       dev->dmasound.dma_running = 0;
+
        /* start DMA now*/
-       dev->inresume = 0;
+       dev->insuspend = 0;
        saa7134_set_dmabits(dev);
        spin_unlock_irqrestore(&dev->slock, flags);
 
        return 0;
 }
+#endif
 
 /* ----------------------------------------------------------- */
 
@@ -1262,8 +1288,10 @@ static struct pci_driver saa7134_pci_driver = {
        .id_table = saa7134_pci_tbl,
        .probe    = saa7134_initdev,
        .remove   = __devexit_p(saa7134_finidev),
+#ifdef CONFIG_PM
        .suspend  = saa7134_suspend,
        .resume   = saa7134_resume
+#endif
 };
 
 static int saa7134_init(void)
index 34ca874..75d0c5b 100644 (file)
@@ -284,17 +284,6 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_S_CTRL:
                return saa7134_common_ioctl(dev, cmd, arg);
 
-       case VIDIOC_S_MPEGCOMP:
-               printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
-                                   "Replace with VIDIOC_S_EXT_CTRLS!");
-               saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg);
-               ts_init_encoder(dev);
-               return 0;
-       case VIDIOC_G_MPEGCOMP:
-               printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
-                                   "Replace with VIDIOC_G_EXT_CTRLS!");
-               saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
-               return 0;
        case VIDIOC_S_EXT_CTRLS:
                /* count == 0 is abused in saa6752hs.c, so that special
                   case is handled here explicitly. */
@@ -342,7 +331,6 @@ static struct video_device saa7134_empress_template =
        .name          = "saa7134-empress",
        .type          = 0 /* FIXME */,
        .type2         = 0 /* FIXME */,
-       .hardware      = 0,
        .fops          = &ts_fops,
        .minor         = -1,
 };
index 80d2644..3abaa1b 100644 (file)
@@ -44,6 +44,14 @@ module_param(ir_rc5_remote_gap, int, 0644);
 static int ir_rc5_key_timeout = 115;
 module_param(ir_rc5_key_timeout, int, 0644);
 
+static int repeat_delay = 500;
+module_param(repeat_delay, int, 0644);
+MODULE_PARM_DESC(repeat_delay, "delay before key repeat started");
+static int repeat_period = 33;
+module_param(repeat_period, int, 0644);
+MODULE_PARM_DESC(repeat_period, "repeat period between"
+    "keypresses when key is down");
+
 #define dprintk(fmt, arg...)   if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
@@ -59,6 +67,13 @@ static int build_key(struct saa7134_dev *dev)
        struct card_ir *ir = dev->remote;
        u32 gpio, data;
 
+       /* here comes the additional handshake steps for some cards */
+       switch (dev->board) {
+       case SAA7134_BOARD_GOTVIEW_7135:
+               saa_setb(SAA7134_GPIO_GPSTATUS1, 0x80);
+               saa_clearb(SAA7134_GPIO_GPSTATUS1, 0x80);
+               break;
+       }
        /* rising SAA7134_GPIO_GPRESCAN reads the status */
        saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
        saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
@@ -159,7 +174,7 @@ static void saa7134_input_timer(unsigned long data)
        mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
-static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
+void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
 {
        if (ir->polling) {
                setup_timer(&ir->timer, saa7134_input_timer,
@@ -182,7 +197,7 @@ static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
        }
 }
 
-static void saa7134_ir_stop(struct saa7134_dev *dev)
+void saa7134_ir_stop(struct saa7134_dev *dev)
 {
        if (dev->remote->polling)
                del_timer_sync(&dev->remote->timer);
@@ -285,10 +300,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                break;
        case SAA7134_BOARD_GOTVIEW_7135:
                ir_codes     = ir_codes_gotview7135;
-               mask_keycode = 0x0003EC;
-               mask_keyup   = 0x008000;
+               mask_keycode = 0x0003CC;
                mask_keydown = 0x000010;
-               polling      = 50; // ms
+               polling      = 5; /* ms */
+               saa_setb(SAA7134_GPIO_GPMODE1, 0x80);
                break;
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
        case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
@@ -386,6 +401,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        if (err)
                goto err_out_stop;
 
+       /* the remote isn't as bouncy as a keyboard */
+       ir->dev->rep[REP_DELAY] = repeat_delay;
+       ir->dev->rep[REP_PERIOD] = repeat_period;
+
        return 0;
 
  err_out_stop:
index 1b9e39a..f8e304c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/kthread.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/freezer.h>
 #include <asm/div64.h>
 
 #include "saa7134-reg.h"
@@ -231,7 +232,7 @@ static void mute_input_7134(struct saa7134_dev *dev)
        }
 
        if (dev->hw_mute  == mute &&
-               dev->hw_input == in && !dev->inresume) {
+               dev->hw_input == in && !dev->insuspend) {
                dprintk("mute/input: nothing to do [mute=%d,input=%s]\n",
                        mute,in->name);
                return;
@@ -502,13 +503,17 @@ static int tvaudio_thread(void *data)
        unsigned int i, audio, nscan;
        int max1,max2,carrier,rx,mode,lastmode,default_carrier;
 
-       allow_signal(SIGTERM);
+
+       set_freezable();
+
        for (;;) {
                tvaudio_sleep(dev,-1);
-               if (kthread_should_stop() || signal_pending(current))
+               if (kthread_should_stop())
                        goto done;
 
        restart:
+               try_to_freeze();
+
                dev->thread.scan1 = dev->thread.scan2;
                dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
                dev->tvaudio  = NULL;
@@ -612,9 +617,12 @@ static int tvaudio_thread(void *data)
 
                lastmode = 42;
                for (;;) {
+
+                       try_to_freeze();
+
                        if (tvaudio_sleep(dev,5000))
                                goto restart;
-                       if (kthread_should_stop() || signal_pending(current))
+                       if (kthread_should_stop())
                                break;
                        if (UNSET == dev->thread.mode) {
                                rx = tvaudio_getstereo(dev,&tvaudio[i]);
@@ -630,6 +638,7 @@ static int tvaudio_thread(void *data)
        }
 
  done:
+       dev->thread.stopped = 1;
        return 0;
 }
 
@@ -777,7 +786,8 @@ static int tvaudio_thread_ddep(void *data)
        struct saa7134_dev *dev = data;
        u32 value, norms, clock;
 
-       allow_signal(SIGTERM);
+
+       set_freezable();
 
        clock = saa7134_boards[dev->board].audio_clock;
        if (UNSET != audio_clock_override)
@@ -790,10 +800,13 @@ static int tvaudio_thread_ddep(void *data)
 
        for (;;) {
                tvaudio_sleep(dev,-1);
-               if (kthread_should_stop() || signal_pending(current))
+               if (kthread_should_stop())
                        goto done;
 
        restart:
+
+               try_to_freeze();
+
                dev->thread.scan1 = dev->thread.scan2;
                dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
 
@@ -870,6 +883,7 @@ static int tvaudio_thread_ddep(void *data)
        }
 
  done:
+       dev->thread.stopped = 1;
        return 0;
 }
 
@@ -997,7 +1011,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 int saa7134_tvaudio_fini(struct saa7134_dev *dev)
 {
        /* shutdown tvaudio thread */
-       if (dev->thread.thread)
+       if (dev->thread.thread && !dev->thread.stopped)
                kthread_stop(dev->thread.thread);
 
        saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
@@ -1013,7 +1027,9 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
        } else if (dev->thread.thread) {
                dev->thread.mode = UNSET;
                dev->thread.scan2++;
-               wake_up_process(dev->thread.thread);
+
+               if (!dev->insuspend && !dev->thread.stopped)
+                       wake_up_process(dev->thread.thread);
        } else {
                dev->automute = 0;
                saa7134_tvaudio_setmute(dev);
index 471b927..3b9ffb4 100644 (file)
@@ -560,15 +560,8 @@ void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
 
        dev->crop_current = dev->crop_defrect;
 
-       saa7134_set_decoder(dev);
+       saa7134_set_tvnorm_hw(dev);
 
-       if (card_in(dev, dev->ctl_input).tv) {
-               if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
-                               && ((card(dev).tuner_config == 1)
-                               ||  (card(dev).tuner_config == 2)))
-                       saa7134_set_gpio(dev, 22, 5);
-               saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &norm->id);
-       }
 }
 
 static void video_mux(struct saa7134_dev *dev, int input)
@@ -579,7 +572,8 @@ static void video_mux(struct saa7134_dev *dev, int input)
        saa7134_tvaudio_setinput(dev, &card_in(dev, input));
 }
 
-void saa7134_set_decoder(struct saa7134_dev *dev)
+
+static void saa7134_set_decoder(struct saa7134_dev *dev)
 {
        int luma_control, sync_control, mux;
 
@@ -630,6 +624,19 @@ void saa7134_set_decoder(struct saa7134_dev *dev)
        saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
 }
 
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
+{
+       saa7134_set_decoder(dev);
+
+       if (card_in(dev, dev->ctl_input).tv) {
+               if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
+                               && ((card(dev).tuner_config == 1)
+                               ||  (card(dev).tuner_config == 2)))
+                       saa7134_set_gpio(dev, 22, 5);
+               saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
+       }
+}
+
 static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
 {
        static const struct {
@@ -2352,7 +2359,6 @@ struct video_device saa7134_video_template =
        .name          = "saa7134-video",
        .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
                         VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-       .hardware      = 0,
        .fops          = &video_fops,
        .minor         = -1,
 };
@@ -2361,7 +2367,6 @@ struct video_device saa7134_vbi_template =
 {
        .name          = "saa7134-vbi",
        .type          = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
-       .hardware      = 0,
        .fops          = &video_fops,
        .minor         = -1,
 };
@@ -2370,7 +2375,6 @@ struct video_device saa7134_radio_template =
 {
        .name          = "saa7134-radio",
        .type          = VID_TYPE_TUNER,
-       .hardware      = 0,
        .fops          = &radio_fops,
        .minor         = -1,
 };
index 28ec680..66a390c 100644 (file)
@@ -333,6 +333,7 @@ struct saa7134_thread {
        unsigned int               scan1;
        unsigned int               scan2;
        unsigned int               mode;
+       unsigned int               stopped;
 };
 
 /* buffer for one video/vbi/ts frame */
@@ -524,7 +525,7 @@ struct saa7134_dev {
        unsigned int               hw_mute;
        int                        last_carrier;
        int                        nosignal;
-       unsigned int               inresume;
+       unsigned int               insuspend;
 
        /* SAA7134_MPEG_* */
        struct saa7134_ts          ts;
@@ -632,7 +633,7 @@ extern struct video_device saa7134_radio_template;
 
 void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm);
 int saa7134_videoport_init(struct saa7134_dev *dev);
-void saa7134_set_decoder(struct saa7134_dev *dev);
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
 
 int saa7134_common_ioctl(struct saa7134_dev *dev,
                         unsigned int cmd, void *arg);
@@ -706,6 +707,8 @@ int  saa7134_input_init1(struct saa7134_dev *dev);
 void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
 void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
+void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir);
+void saa7134_ir_stop(struct saa7134_dev *dev);
 
 
 /*
index 93fb04e..d5d7d6c 100644 (file)
@@ -1231,7 +1231,6 @@ static struct video_device se401_template = {
        .owner =        THIS_MODULE,
        .name =         "se401 USB camera",
        .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_SE401,
        .fops =         &se401_fops,
 };
 
index 6991e06..5118479 100644 (file)
@@ -3319,7 +3319,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        strcpy(cam->v4ldev->name, "SN9C1xx PC Camera");
        cam->v4ldev->owner = THIS_MODULE;
        cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = 0;
        cam->v4ldev->fops = &sn9c102_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
index eb22046..3fb85af 100644 (file)
@@ -1917,7 +1917,6 @@ static const struct file_operations saa_fops = {
 static struct video_device saa_template = {
        .name = "SAA7146A",
        .type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY,
-       .hardware = VID_HARDWARE_SAA7146,
        .fops = &saa_fops,
        .minor = -1,
 };
index 9e009a7..afc32aa 100644 (file)
@@ -1398,7 +1398,6 @@ static struct video_device stv680_template = {
        .owner =        THIS_MODULE,
        .name =         "STV0680 USB camera",
        .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_SE401,
        .fops =         &stv680_fops,
        .release =      video_device_release,
        .minor =        -1,
index 9484308..6a77760 100644 (file)
@@ -113,7 +113,7 @@ static void fe_standby(struct tuner *t)
 static int fe_has_signal(struct tuner *t)
 {
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-       u16 strength;
+       u16 strength = 0;
 
        if (fe_tuner_ops->get_rf_strength)
                fe_tuner_ops->get_rf_strength(&t->fe, &strength);
index 37ce36b..fb434b5 100644 (file)
@@ -952,7 +952,6 @@ static const struct file_operations usbvideo_fops = {
 static const struct video_device usbvideo_template = {
        .owner =      THIS_MODULE,
        .type =       VID_TYPE_CAPTURE,
-       .hardware =   VID_HARDWARE_CPIA,
        .fops =       &usbvideo_fops,
 };
 
index db3c9e3..da1ba02 100644 (file)
@@ -1074,7 +1074,6 @@ static struct video_device vicam_template = {
        .owner          = THIS_MODULE,
        .name           = "ViCam-based USB Camera",
        .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_VICAM,
        .fops           = &vicam_fops,
        .minor          = -1,
 };
index e2f3c01..36e689f 100644 (file)
@@ -1400,7 +1400,6 @@ static const struct file_operations usbvision_fops = {
 static struct video_device usbvision_video_template = {
        .owner             = THIS_MODULE,
        .type           = VID_TYPE_TUNER | VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_USBVISION,
        .fops           = &usbvision_fops,
        .name           = "usbvision-video",
        .release        = video_device_release,
@@ -1455,7 +1454,6 @@ static struct video_device usbvision_radio_template=
 {
        .owner             = THIS_MODULE,
        .type           = VID_TYPE_TUNER,
-       .hardware       = VID_HARDWARE_USBVISION,
        .fops           = &usbvision_radio_fops,
        .name           = "usbvision-radio",
        .release        = video_device_release,
@@ -1492,7 +1490,6 @@ static struct video_device usbvision_vbi_template=
 {
        .owner             = THIS_MODULE,
        .type           = VID_TYPE_TUNER,
-       .hardware       = VID_HARDWARE_USBVISION,
        .fops           = &usbvision_vbi_fops,
        .release        = video_device_release,
        .name           = "usbvision-vbi",
index 3212492..1141b4b 100644 (file)
@@ -317,8 +317,6 @@ static const char *v4l2_ioctls[] = {
        [_IOC_NR(VIDIOC_ENUM_FMT)]         = "VIDIOC_ENUM_FMT",
        [_IOC_NR(VIDIOC_G_FMT)]            = "VIDIOC_G_FMT",
        [_IOC_NR(VIDIOC_S_FMT)]            = "VIDIOC_S_FMT",
-       [_IOC_NR(VIDIOC_G_MPEGCOMP)]       = "VIDIOC_G_MPEGCOMP",
-       [_IOC_NR(VIDIOC_S_MPEGCOMP)]       = "VIDIOC_S_MPEGCOMP",
        [_IOC_NR(VIDIOC_REQBUFS)]          = "VIDIOC_REQBUFS",
        [_IOC_NR(VIDIOC_QUERYBUF)]         = "VIDIOC_QUERYBUF",
        [_IOC_NR(VIDIOC_G_FBUF)]           = "VIDIOC_G_FBUF",
index 5599a36..89a44f1 100644 (file)
@@ -967,6 +967,7 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -985,7 +986,6 @@ EXPORT_SYMBOL_GPL(videobuf_reqbufs);
 EXPORT_SYMBOL_GPL(videobuf_querybuf);
 EXPORT_SYMBOL_GPL(videobuf_qbuf);
 EXPORT_SYMBOL_GPL(videobuf_dqbuf);
-EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
 EXPORT_SYMBOL_GPL(videobuf_streamon);
 EXPORT_SYMBOL_GPL(videobuf_streamoff);
 
index 3eb6123..9ab94a7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
+#include <linux/scatterlist.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
@@ -60,12 +61,13 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
        sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
        if (NULL == sglist)
                return NULL;
+       sg_init_table(sglist, nr_pages);
        for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
                pg = vmalloc_to_page(virt);
                if (NULL == pg)
                        goto err;
                BUG_ON(PageHighMem(pg));
-               sglist[i].page   = pg;
+               sg_set_page(&sglist[i], pg);
                sglist[i].length = PAGE_SIZE;
        }
        return sglist;
@@ -86,13 +88,14 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
        sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL);
        if (NULL == sglist)
                return NULL;
+       sg_init_table(sglist, nr_pages);
 
        if (NULL == pages[0])
                goto nopage;
        if (PageHighMem(pages[0]))
                /* DMA to highmem pages might not work */
                goto highmem;
-       sglist[0].page   = pages[0];
+       sg_set_page(&sglist[0], pages[0]);
        sglist[0].offset = offset;
        sglist[0].length = PAGE_SIZE - offset;
        for (i = 1; i < nr_pages; i++) {
@@ -100,7 +103,7 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
                        goto nopage;
                if (PageHighMem(pages[i]))
                        goto highmem;
-               sglist[i].page   = pages[i];
+               sg_set_page(&sglist[i], pages[i]);
                sglist[i].length = PAGE_SIZE;
        }
        return sglist;
index f2bbd7a..87951ec 100644 (file)
@@ -86,8 +86,8 @@ videocodec_attach (struct videocodec_master *master)
        }
 
        dprintk(2,
-               "videocodec_attach: '%s', type: %x, flags %lx, magic %lx\n",
-               master->name, master->type, master->flags, master->magic);
+               "videocodec_attach: '%s', flags %lx, magic %lx\n",
+               master->name, master->flags, master->magic);
 
        if (!h) {
                dprintk(1,
index 8d8e517..9611c39 100644 (file)
@@ -1313,48 +1313,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                ret=vfd->vidioc_cropcap(file, fh, p);
                break;
        }
-       case VIDIOC_G_MPEGCOMP:
-       {
-               struct v4l2_mpeg_compression *p=arg;
-
-               /*FIXME: Several fields not shown */
-               if (!vfd->vidioc_g_mpegcomp)
-                       break;
-               ret=vfd->vidioc_g_mpegcomp(file, fh, p);
-               if (!ret)
-                       dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d,"
-                                       " ts_pid_video=%d, ts_pid_pcr=%d, "
-                                       "ps_size=%d, au_sample_rate=%d, "
-                                       "au_pesid=%c, vi_frame_rate=%d, "
-                                       "vi_frames_per_gop=%d, "
-                                       "vi_bframes_count=%d, vi_pesid=%c\n",
-                                       p->ts_pid_pmt,p->ts_pid_audio,
-                                       p->ts_pid_video,p->ts_pid_pcr,
-                                       p->ps_size, p->au_sample_rate,
-                                       p->au_pesid, p->vi_frame_rate,
-                                       p->vi_frames_per_gop,
-                                       p->vi_bframes_count, p->vi_pesid);
-               break;
-       }
-       case VIDIOC_S_MPEGCOMP:
-       {
-               struct v4l2_mpeg_compression *p=arg;
-               /*FIXME: Several fields not shown */
-               if (!vfd->vidioc_s_mpegcomp)
-                       break;
-               dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, "
-                               "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, "
-                               "au_sample_rate=%d, au_pesid=%c, "
-                               "vi_frame_rate=%d, vi_frames_per_gop=%d, "
-                               "vi_bframes_count=%d, vi_pesid=%c\n",
-                               p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
-                               p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
-                               p->au_pesid, p->vi_frame_rate,
-                               p->vi_frames_per_gop, p->vi_bframes_count,
-                               p->vi_pesid);
-               ret=vfd->vidioc_s_mpegcomp(file, fh, p);
-               break;
-       }
        case VIDIOC_G_JPEGCOMP:
        {
                struct v4l2_jpegcompression *p=arg;
index b532aa2..ee73dc7 100644 (file)
@@ -1119,7 +1119,6 @@ static const struct file_operations vivi_fops = {
 static struct video_device vivi = {
        .name           = "vivi",
        .type           = VID_TYPE_CAPTURE,
-       .hardware       = 0,
        .fops           = &vivi_fops,
        .minor          = -1,
 //     .release        = video_device_release,
index 4736640..08aaae0 100644 (file)
@@ -196,7 +196,6 @@ static struct video_device w9966_template = {
        .owner          = THIS_MODULE,
        .name           = W9966_DRIVERNAME,
        .type           = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
-       .hardware       = VID_HARDWARE_W9966,
        .fops           = &w9966_fops,
 };
 
index 9e7f3e6..2ae1430 100644 (file)
@@ -3549,7 +3549,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
        cam->v4ldev->owner = THIS_MODULE;
        cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = VID_HARDWARE_W9968CF;
        cam->v4ldev->fops = &w9968cf_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
index 08a93c3..2c5665c 100644 (file)
@@ -1985,7 +1985,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
        cam->v4ldev->owner = THIS_MODULE;
        cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = 0;
        cam->v4ldev->fops = &zc0301_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
index 48da36a..6e0ac4c 100644 (file)
@@ -1235,8 +1235,14 @@ zoran_setup_videocodec (struct zoran *zr,
                return m;
        }
 
-       m->magic = 0L; /* magic not used */
-       m->type = VID_HARDWARE_ZR36067;
+       /* magic and type are unused for master struct. Makes sense only at
+          codec structs.
+          In the past, .type were initialized to the old V4L1 .hardware
+          value, as VID_HARDWARE_ZR36067
+        */
+       m->magic = 0L;
+       m->type = 0;
+
        m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER;
        strncpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
        m->data = zr;
index 419e5af..dd3d7d2 100644 (file)
@@ -60,7 +60,6 @@
 
 #include <linux/spinlock.h>
 #define     MAP_NR(x)       virt_to_page(x)
-#define     ZORAN_HARDWARE  VID_HARDWARE_ZR36067
 #define     ZORAN_VID_TYPE  ( \
                                VID_TYPE_CAPTURE | \
                                VID_TYPE_OVERLAY | \
@@ -4659,7 +4658,6 @@ struct video_device zoran_template __devinitdata = {
 #ifdef CONFIG_VIDEO_V4L2
        .type2 = ZORAN_V4L2_VID_FLAGS,
 #endif
-       .hardware = ZORAN_HARDWARE,
        .fops = &zoran_fops,
        .release = &zoran_vdev_release,
        .minor = -1
index a5d0354..9203a0b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/blkdev.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
+#include <linux/scatterlist.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -153,19 +154,21 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
                        blk_queue_max_hw_segments(mq->queue, bouncesz / 512);
                        blk_queue_max_segment_size(mq->queue, bouncesz);
 
-                       mq->sg = kzalloc(sizeof(struct scatterlist),
+                       mq->sg = kmalloc(sizeof(struct scatterlist),
                                GFP_KERNEL);
                        if (!mq->sg) {
                                ret = -ENOMEM;
                                goto cleanup_queue;
                        }
+                       sg_init_table(mq->sg, 1);
 
-                       mq->bounce_sg = kzalloc(sizeof(struct scatterlist) *
+                       mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
                                bouncesz / 512, GFP_KERNEL);
                        if (!mq->bounce_sg) {
                                ret = -ENOMEM;
                                goto cleanup_queue;
                        }
+                       sg_init_table(mq->bounce_sg, bouncesz / 512);
                }
        }
 #endif
@@ -302,12 +305,12 @@ static void copy_sg(struct scatterlist *dst, unsigned int dst_len,
                BUG_ON(dst_len == 0);
 
                if (dst_size == 0) {
-                       dst_buf = page_address(dst->page) + dst->offset;
+                       dst_buf = sg_virt(dst);
                        dst_size = dst->length;
                }
 
                if (src_size == 0) {
-                       src_buf = page_address(src->page) + src->offset;
+                       src_buf = sg_virt(dst);
                        src_size = src->length;
                }
 
@@ -353,9 +356,7 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
                return 1;
        }
 
-       mq->sg[0].page = virt_to_page(mq->bounce_buf);
-       mq->sg[0].offset = offset_in_page(mq->bounce_buf);
-       mq->sg[0].length = 0;
+       sg_init_one(mq->sg, mq->bounce_buf, 0);
 
        while (sg_len) {
                mq->sg[0].length += mq->bounce_sg[sg_len - 1].length;
index 7a452c2..b1edcef 100644 (file)
@@ -149,7 +149,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
 
                sg = &data->sg[i];
 
-               sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+               sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
                amount = min(size, sg->length);
                size -= amount;
 
@@ -226,7 +226,7 @@ static void at91_mci_pre_dma_read(struct at91mci_host *host)
                sg = &data->sg[host->transfer_index++];
                pr_debug("sg = %p\n", sg);
 
-               sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE);
+               sg->dma_address = dma_map_page(NULL, sg_page(sg), sg->offset, sg->length, DMA_FROM_DEVICE);
 
                pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
 
@@ -283,7 +283,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
                        int index;
 
                        /* Swap the contents of the buffer */
-                       buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+                       buffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
                        pr_debug("buffer = %p, length = %d\n", buffer, sg->length);
 
                        for (index = 0; index < (sg->length / 4); index++)
@@ -292,7 +292,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
                        kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
                }
 
-               flush_dcache_page(sg->page);
+               flush_dcache_page(sg_page(sg));
        }
 
        /* Is there another transfer to trigger? */
index 92c4d0d..bcbb6d2 100644 (file)
@@ -340,7 +340,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
 
        /* This is the pointer to the data buffer */
        sg = &data->sg[host->pio.index];
-       sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+       sg_ptr = sg_virt(sg) + host->pio.offset;
 
        /* This is the space left inside the buffer */
        sg_len = data->sg[host->pio.index].length - host->pio.offset;
@@ -400,7 +400,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
 
        if (host->pio.index < host->dma.len) {
                sg = &data->sg[host->pio.index];
-               sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+               sg_ptr = sg_virt(sg) + host->pio.offset;
 
                /* This is the space left inside the buffer */
                sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
@@ -613,14 +613,11 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
 
                        if (host->flags & HOST_F_XMIT){
                                ret = au1xxx_dbdma_put_source_flags(channel,
-                                       (void *) (page_address(sg->page) +
-                                                 sg->offset),
-                                       len, flags);
+                                       (void *) sg_virt(sg), len, flags);
                        }
                        else {
                                ret = au1xxx_dbdma_put_dest_flags(channel,
-                                       (void *) (page_address(sg->page) +
-                                                 sg->offset),
+                                       (void *) sg_virt(sg),
                                        len, flags);
                        }
 
index 6ebc41e..fc72e1f 100644 (file)
@@ -262,7 +262,7 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
                }
 
                /* Convert back to virtual address */
-               host->data_ptr = (u16*)(page_address(data->sg->page) + data->sg->offset);
+               host->data_ptr = (u16*)sg_virt(sg);
                host->data_cnt = 0;
 
                clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
index 7ae18ea..12c2d80 100644 (file)
@@ -813,7 +813,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                                        && dir == DMA_FROM_DEVICE)
                                dir = DMA_BIDIRECTIONAL;
 
-                       dma_addr = dma_map_page(dma_dev, sg->page, 0,
+                       dma_addr = dma_map_page(dma_dev, sg_page(sg), 0,
                                                PAGE_SIZE, dir);
                        if (direction == DMA_TO_DEVICE)
                                t->tx_dma = dma_addr + sg->offset;
@@ -822,7 +822,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                }
 
                /* allow pio too; we don't allow highmem */
-               kmap_addr = kmap(sg->page);
+               kmap_addr = kmap(sg_page(sg));
                if (direction == DMA_TO_DEVICE)
                        t->tx_buf = kmap_addr + sg->offset;
                else
@@ -855,8 +855,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
 
                /* discard mappings */
                if (direction == DMA_FROM_DEVICE)
-                       flush_kernel_dcache_page(sg->page);
-               kunmap(sg->page);
+                       flush_kernel_dcache_page(sg_page(sg));
+               kunmap(sg_page(sg));
                if (dma_dev)
                        dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir);
 
index 000e6a9..0f39c49 100644 (file)
@@ -169,7 +169,7 @@ static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flag
        struct scatterlist *sg = host->sg_ptr;
 
        local_irq_save(*flags);
-       return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+       return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
 }
 
 static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
index 60a67df..971e18b 100644 (file)
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/clk.h>
+#include <linux/scatterlist.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/scatterlist.h>
 #include <asm/mach-types.h>
 
 #include <asm/arch/board.h>
@@ -383,7 +383,7 @@ mmc_omap_sg_to_buf(struct mmc_omap_host *host)
 
        sg = host->data->sg + host->sg_idx;
        host->buffer_bytes_left = sg->length;
-       host->buffer = page_address(sg->page) + sg->offset;
+       host->buffer = sg_virt(sg);
        if (host->buffer_bytes_left > host->total_bytes_left)
                host->buffer_bytes_left = host->total_bytes_left;
 }
index b397121..d7c5b94 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/highmem.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
 
 #include <linux/mmc/host.h>
 
@@ -231,7 +232,7 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
 
 static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
 {
-       return page_address(host->cur_sg->page) + host->cur_sg->offset;
+       return sg_virt(host->cur_sg);
 }
 
 static inline int sdhci_next_sg(struct sdhci_host* host)
index 9b90479..c11a3d2 100644 (file)
@@ -192,7 +192,7 @@ static void tifm_sd_transfer_data(struct tifm_sd *host)
                }
                off = sg[host->sg_pos].offset + host->block_pos;
 
-               pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+               pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT);
                p_off = offset_in_page(off);
                p_cnt = PAGE_SIZE - p_off;
                p_cnt = min(p_cnt, cnt);
@@ -241,18 +241,18 @@ static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
                }
                off = sg[host->sg_pos].offset + host->block_pos;
 
-               pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+               pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT);
                p_off = offset_in_page(off);
                p_cnt = PAGE_SIZE - p_off;
                p_cnt = min(p_cnt, cnt);
                p_cnt = min(p_cnt, t_size);
 
                if (r_data->flags & MMC_DATA_WRITE)
-                       tifm_sd_copy_page(host->bounce_buf.page,
+                       tifm_sd_copy_page(sg_page(&host->bounce_buf),
                                          r_data->blksz - t_size,
                                          pg, p_off, p_cnt);
                else if (r_data->flags & MMC_DATA_READ)
-                       tifm_sd_copy_page(pg, p_off, host->bounce_buf.page,
+                       tifm_sd_copy_page(pg, p_off, sg_page(&host->bounce_buf),
                                          r_data->blksz - t_size, p_cnt);
 
                t_size -= p_cnt;
index 80db11c..fa4c8c5 100644 (file)
@@ -269,7 +269,7 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
 
 static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
 {
-       return page_address(host->cur_sg->page) + host->cur_sg->offset;
+       return sg_virt(host->cur_sg);
 }
 
 static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@@ -283,7 +283,7 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
        len = data->sg_len;
 
        for (i = 0; i < len; i++) {
-               sgbuf = page_address(sg[i].page) + sg[i].offset;
+               sgbuf = sg_virt(&sg[i]);
                memcpy(dmabuf, sgbuf, sg[i].length);
                dmabuf += sg[i].length;
        }
@@ -300,7 +300,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
        len = data->sg_len;
 
        for (i = 0; i < len; i++) {
-               sgbuf = page_address(sg[i].page) + sg[i].offset;
+               sgbuf = sg_virt(&sg[i]);
                memcpy(sgbuf, dmabuf, sg[i].length);
                dmabuf += sg[i].length;
        }
index 3aa3dca..a9eb1c5 100644 (file)
@@ -85,6 +85,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
 static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
                        size_t len);
 
+static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
 static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
 #include "fwh_lock.h"
@@ -641,73 +642,13 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
 /*
  *  *********** CHIP ACCESS FUNCTIONS ***********
  */
-
-static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
+static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct cfi_private *cfi = map->fldrv_priv;
        map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01);
-       unsigned long timeo;
        struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
-
- resettime:
-       timeo = jiffies + HZ;
- retry:
-       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
-               /*
-                * OK. We have possibility for contension on the write/erase
-                * operations which are global to the real chip and not per
-                * partition.  So let's fight it over in the partition which
-                * currently has authority on the operation.
-                *
-                * The rules are as follows:
-                *
-                * - any write operation must own shared->writing.
-                *
-                * - any erase operation must own _both_ shared->writing and
-                *   shared->erasing.
-                *
-                * - contension arbitration is handled in the owner's context.
-                *
-                * The 'shared' struct can be read and/or written only when
-                * its lock is taken.
-                */
-               struct flchip_shared *shared = chip->priv;
-               struct flchip *contender;
-               spin_lock(&shared->lock);
-               contender = shared->writing;
-               if (contender && contender != chip) {
-                       /*
-                        * The engine to perform desired operation on this
-                        * partition is already in use by someone else.
-                        * Let's fight over it in the context of the chip
-                        * currently using it.  If it is possible to suspend,
-                        * that other partition will do just that, otherwise
-                        * it'll happily send us to sleep.  In any case, when
-                        * get_chip returns success we're clear to go ahead.
-                        */
-                       int ret = spin_trylock(contender->mutex);
-                       spin_unlock(&shared->lock);
-                       if (!ret)
-                               goto retry;
-                       spin_unlock(chip->mutex);
-                       ret = get_chip(map, contender, contender->start, mode);
-                       spin_lock(chip->mutex);
-                       if (ret) {
-                               spin_unlock(contender->mutex);
-                               return ret;
-                       }
-                       timeo = jiffies + HZ;
-                       spin_lock(&shared->lock);
-                       spin_unlock(contender->mutex);
-               }
-
-               /* We now own it */
-               shared->writing = chip;
-               if (mode == FL_ERASING)
-                       shared->erasing = chip;
-               spin_unlock(&shared->lock);
-       }
+       unsigned long timeo = jiffies + HZ;
 
        switch (chip->state) {
 
@@ -722,16 +663,11 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                        if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS))
                                break;
 
-                       if (time_after(jiffies, timeo)) {
-                               printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n",
-                                      map->name, status.x[0]);
-                               return -EIO;
-                       }
                        spin_unlock(chip->mutex);
                        cfi_udelay(1);
                        spin_lock(chip->mutex);
                        /* Someone else might have been playing with it. */
-                       goto retry;
+                       return -EAGAIN;
                }
 
        case FL_READY:
@@ -809,10 +745,82 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                schedule();
                remove_wait_queue(&chip->wq, &wait);
                spin_lock(chip->mutex);
-               goto resettime;
+               return -EAGAIN;
        }
 }
 
+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
+{
+       int ret;
+
+ retry:
+       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
+                          || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
+               /*
+                * OK. We have possibility for contention on the write/erase
+                * operations which are global to the real chip and not per
+                * partition.  So let's fight it over in the partition which
+                * currently has authority on the operation.
+                *
+                * The rules are as follows:
+                *
+                * - any write operation must own shared->writing.
+                *
+                * - any erase operation must own _both_ shared->writing and
+                *   shared->erasing.
+                *
+                * - contention arbitration is handled in the owner's context.
+                *
+                * The 'shared' struct can be read and/or written only when
+                * its lock is taken.
+                */
+               struct flchip_shared *shared = chip->priv;
+               struct flchip *contender;
+               spin_lock(&shared->lock);
+               contender = shared->writing;
+               if (contender && contender != chip) {
+                       /*
+                        * The engine to perform desired operation on this
+                        * partition is already in use by someone else.
+                        * Let's fight over it in the context of the chip
+                        * currently using it.  If it is possible to suspend,
+                        * that other partition will do just that, otherwise
+                        * it'll happily send us to sleep.  In any case, when
+                        * get_chip returns success we're clear to go ahead.
+                        */
+                       ret = spin_trylock(contender->mutex);
+                       spin_unlock(&shared->lock);
+                       if (!ret)
+                               goto retry;
+                       spin_unlock(chip->mutex);
+                       ret = chip_ready(map, contender, contender->start, mode);
+                       spin_lock(chip->mutex);
+
+                       if (ret == -EAGAIN) {
+                               spin_unlock(contender->mutex);
+                               goto retry;
+                       }
+                       if (ret) {
+                               spin_unlock(contender->mutex);
+                               return ret;
+                       }
+                       spin_lock(&shared->lock);
+                       spin_unlock(contender->mutex);
+               }
+
+               /* We now own it */
+               shared->writing = chip;
+               if (mode == FL_ERASING)
+                       shared->erasing = chip;
+               spin_unlock(&shared->lock);
+       }
+       ret = chip_ready(map, chip, adr, mode);
+       if (ret == -EAGAIN)
+               goto retry;
+
+       return ret;
+}
+
 static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
 {
        struct cfi_private *cfi = map->fldrv_priv;
index 8f9c3ba..246d451 100644 (file)
@@ -300,7 +300,7 @@ config MTD_NAND_PLATFORM
          via platform_data.
 
 config MTD_ALAUDA
-       tristate "MTD driver for Olympus MAUSB-10 and Fijufilm DPC-R1"
+       tristate "MTD driver for Olympus MAUSB-10 and Fujifilm DPC-R1"
        depends on MTD_NAND && USB
        help
          These two (and possibly other) Alauda-based cardreaders for
index ab9f5c5..0e72153 100644 (file)
@@ -220,7 +220,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
                }
        }
        /* If the parity is wrong, no rescue possible */
-       return parity ? -1 : nerr;
+       return parity ? -EBADMSG : nerr;
 }
 
 static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
@@ -1034,7 +1034,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
                WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
        else
                WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-       if (no_ecc_failures && (ret == -1)) {
+       if (no_ecc_failures && (ret == -EBADMSG)) {
                printk(KERN_ERR "suppressing ECC failure\n");
                ret = 0;
        }
index b4e0e77..e29c1da 100644 (file)
@@ -789,7 +789,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
                int stat;
 
                stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-               if (stat == -1)
+               if (stat < 0)
                        mtd->ecc_stats.failed++;
                else
                        mtd->ecc_stats.corrected += stat;
@@ -833,7 +833,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                int stat;
 
                stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-               if (stat == -1)
+               if (stat < 0)
                        mtd->ecc_stats.failed++;
                else
                        mtd->ecc_stats.corrected += stat;
@@ -874,7 +874,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
                chip->read_buf(mtd, oob, eccbytes);
                stat = chip->ecc.correct(mtd, p, oob, NULL);
 
-               if (stat == -1)
+               if (stat < 0)
                        mtd->ecc_stats.failed++;
                else
                        mtd->ecc_stats.corrected += stat;
index fde593e..9003a13 100644 (file)
@@ -189,7 +189,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat,
        if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
                return 1;
 
-       return -1;
+       return -EBADMSG;
 }
 EXPORT_SYMBOL(nand_correct_data);
 
index a757480..10490b4 100644 (file)
@@ -511,7 +511,7 @@ static int init_nandsim(struct mtd_info *mtd)
        }
 
        if (ns->options & OPT_SMALLPAGE) {
-               if (ns->geom.totsz < (64 << 20)) {
+               if (ns->geom.totsz < (32 << 20)) {
                        ns->geom.pgaddrbytes  = 3;
                        ns->geom.secaddrbytes = 2;
                } else {
index 21b921d..66f76e9 100644 (file)
@@ -488,12 +488,24 @@ static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
        readsb(this->IO_ADDR_R, buf, len);
 }
 
+static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       readsl(info->regs + S3C2440_NFDATA, buf, len / 4);
+}
+
 static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
        writesb(this->IO_ADDR_W, buf, len);
 }
 
+static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       writesl(info->regs + S3C2440_NFDATA, buf, len / 4);
+}
+
 /* device management functions */
 
 static int s3c2410_nand_remove(struct platform_device *pdev)
@@ -604,6 +616,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
                info->sel_bit   = S3C2440_NFCONT_nFCE;
                chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
                chip->dev_ready = s3c2440_nand_devready;
+               chip->read_buf  = s3c2440_nand_read_buf;
+               chip->write_buf = s3c2440_nand_write_buf;
                break;
 
        case TYPE_S3C2412:
index 0d89ad5..d64200b 100644 (file)
@@ -88,11 +88,11 @@ do {                                                                        \
 
 /**
  * onenand_lock_handle - Handle Lock scheme
- * @param this         OneNAND device structure
- * @param cmd          The command to be sent
+ * @this:              OneNAND device structure
+ * @cmd:               The command to be sent
  *
  * Send lock command to OneNAND device.
- * The lock scheme is depends on chip type.
+ * The lock scheme depends on chip type.
  */
 static void onenand_lock_handle(struct onenand_chip *this, int cmd)
 {
@@ -131,8 +131,8 @@ static void onenand_lock_handle(struct onenand_chip *this, int cmd)
 
 /**
  * onenand_bootram_handle - Handle BootRAM area
- * @param this         OneNAND device structure
- * @param cmd          The command to be sent
+ * @this:              OneNAND device structure
+ * @cmd:               The command to be sent
  *
  * Emulate BootRAM area. It is possible to do basic operation using BootRAM.
  */
@@ -153,10 +153,10 @@ static void onenand_bootram_handle(struct onenand_chip *this, int cmd)
 
 /**
  * onenand_update_interrupt - Set interrupt register
- * @param this         OneNAND device structure
- * @param cmd          The command to be sent
+ * @this:         OneNAND device structure
+ * @cmd:          The command to be sent
  *
- * Update interrupt register. The status is depends on command.
+ * Update interrupt register. The status depends on command.
  */
 static void onenand_update_interrupt(struct onenand_chip *this, int cmd)
 {
@@ -189,11 +189,12 @@ static void onenand_update_interrupt(struct onenand_chip *this, int cmd)
 }
 
 /**
- * onenand_check_overwrite - Check over-write if happend
- * @param dest         The destination pointer
- * @param src          The source pointer
- * @param count                The length to be check
- * @return             0 on same, otherwise 1
+ * onenand_check_overwrite - Check if over-write happened
+ * @dest:              The destination pointer
+ * @src:               The source pointer
+ * @count:             The length to be check
+ *
+ * Returns:            0 on same, otherwise 1
  *
  * Compare the source with destination
  */
@@ -213,10 +214,10 @@ static int onenand_check_overwrite(void *dest, void *src, size_t count)
 
 /**
  * onenand_data_handle - Handle OneNAND Core and DataRAM
- * @param this         OneNAND device structure
- * @param cmd          The command to be sent
- * @param dataram      Which dataram used
- * @param offset       The offset to OneNAND Core
+ * @this:              OneNAND device structure
+ * @cmd:               The command to be sent
+ * @dataram:           Which dataram used
+ * @offset:            The offset to OneNAND Core
  *
  * Copy data from OneNAND Core to DataRAM (read)
  * Copy data from DataRAM to OneNAND Core (write)
@@ -295,8 +296,8 @@ static void onenand_data_handle(struct onenand_chip *this, int cmd,
 
 /**
  * onenand_command_handle - Handle command
- * @param this         OneNAND device structure
- * @param cmd          The command to be sent
+ * @this:              OneNAND device structure
+ * @cmd:               The command to be sent
  *
  * Emulate OneNAND command.
  */
@@ -350,8 +351,8 @@ static void onenand_command_handle(struct onenand_chip *this, int cmd)
 
 /**
  * onenand_writew - [OneNAND Interface] Emulate write operation
- * @param value                value to write
- * @param addr         address to write
+ * @value:             value to write
+ * @addr:              address to write
  *
  * Write OneNAND register with value
  */
@@ -373,7 +374,7 @@ static void onenand_writew(unsigned short value, void __iomem * addr)
 
 /**
  * flash_init - Initialize OneNAND simulator
- * @param flash                OneNAND simulaotr data strucutres
+ * @flash:             OneNAND simulator data strucutres
  *
  * Initialize OneNAND simulator.
  */
@@ -416,7 +417,7 @@ static int __init flash_init(struct onenand_flash *flash)
 
 /**
  * flash_exit - Clean up OneNAND simulator
- * @param flash                OneNAND simulaotr data strucutres
+ * @flash:             OneNAND simulator data structures
  *
  * Clean up OneNAND simulator.
  */
@@ -424,7 +425,6 @@ static void flash_exit(struct onenand_flash *flash)
 {
        vfree(ONENAND_CORE(flash));
        kfree(flash->base);
-       kfree(flash);
 }
 
 static int __init onenand_sim_init(void)
@@ -449,7 +449,7 @@ static int __init onenand_sim_init(void)
        info->onenand.write_word = onenand_writew;
 
        if (flash_init(&info->flash)) {
-               printk(KERN_ERR "Unable to allocat flash.\n");
+               printk(KERN_ERR "Unable to allocate flash.\n");
                kfree(ffchars);
                kfree(info);
                return -ENOMEM;
index ce34b53..2538816 100644 (file)
@@ -3100,4 +3100,10 @@ config NETPOLL_TRAP
 config NET_POLL_CONTROLLER
        def_bool NETPOLL
 
+config VIRTIO_NET
+       tristate "Virtio network driver (EXPERIMENTAL)"
+       depends on EXPERIMENTAL && VIRTIO
+       ---help---
+         This is the virtual network driver for lguest.  Say Y or M.
+
 endif # NETDEVICES
index 22f78cb..5932620 100644 (file)
@@ -183,7 +183,6 @@ obj-$(CONFIG_ZORRO8390) += zorro8390.o
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_EQUALIZER) += eql.o
-obj-$(CONFIG_LGUEST_NET) += lguest_net.o
 obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
 obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
@@ -243,3 +242,4 @@ obj-$(CONFIG_FS_ENET) += fs_enet/
 
 obj-$(CONFIG_NETXEN_NIC) += netxen/
 obj-$(CONFIG_NIU) += niu.o
+obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
index ed53aaa..ae41973 100644 (file)
@@ -471,7 +471,7 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        len = max(skb->len, ETH_ZLEN);
-       queue = skb->queue_mapping;
+       queue = skb_get_queue_mapping(skb);
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
        netif_stop_subqueue(dev, queue);
 #else
index 2b57820..0fbf1bb 100644 (file)
@@ -751,13 +751,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
                if (mii_head) {
                        mii_tail->mii_next = mip;
                        mii_tail = mip;
-               }
-               else {
+               } else {
                        mii_head = mii_tail = mip;
                        fep->hwp->fec_mii_data = regval;
                }
-       }
-       else {
+       } else {
                retval = 1;
        }
 
@@ -768,14 +766,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
 
 static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
 {
-       int k;
-
        if(!c)
                return;
 
-       for(k = 0; (c+k)->mii_data != mk_mii_end; k++) {
-               mii_queue(dev, (c+k)->mii_data, (c+k)->funct);
-       }
+       for (; c->mii_data != mk_mii_end; c++)
+               mii_queue(dev, c->mii_data, c->funct);
 }
 
 static void mii_parse_sr(uint mii_reg, struct net_device *dev)
@@ -792,7 +787,6 @@ static void mii_parse_sr(uint mii_reg, struct net_device *dev)
                status |= PHY_STAT_FAULT;
        if (mii_reg & 0x0020)
                status |= PHY_STAT_ANC;
-
        *s = status;
 }
 
@@ -1239,7 +1233,6 @@ mii_link_interrupt(int irq, void * dev_id);
 #endif
 
 #if defined(CONFIG_M5272)
-
 /*
  *     Code specific to Coldfire 5272 setup.
  */
@@ -2020,8 +2013,7 @@ static void mii_relink(struct work_struct *work)
                    & (PHY_STAT_100FDX | PHY_STAT_10FDX))
                        duplex = 1;
                fec_restart(dev, duplex);
-       }
-       else
+       } else
                fec_stop(dev);
 
 #if 0
@@ -2119,8 +2111,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
                        fep->phy_id = phytype << 16;
                        mii_queue(dev, mk_mii_read(MII_REG_PHYIR2),
                                                        mii_discover_phy3);
-               }
-               else {
+               } else {
                        fep->phy_addr++;
                        mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
                                                        mii_discover_phy);
@@ -2574,8 +2565,7 @@ fec_restart(struct net_device *dev, int duplex)
        if (duplex) {
                fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;/* MII enable */
                fecp->fec_x_cntrl = 0x04;                 /* FD enable */
-       }
-       else {
+       } else {
                /* MII enable|No Rcv on Xmit */
                fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x06;
                fecp->fec_x_cntrl = 0x00;
diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c
deleted file mode 100644 (file)
index abce2ee..0000000
+++ /dev/null
@@ -1,555 +0,0 @@
-/*D:500
- * The Guest network driver.
- *
- * This is very simple a virtual network driver, and our last Guest driver.
- * The only trick is that it can talk directly to multiple other recipients
- * (ie. other Guests on the same network).  It can also be used with only the
- * Host on the network.
- :*/
-
-/* Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-//#define DEBUG
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/mm_types.h>
-#include <linux/io.h>
-#include <linux/lguest_bus.h>
-
-#define SHARED_SIZE            PAGE_SIZE
-#define MAX_LANS               4
-#define NUM_SKBS               8
-
-/*M:011 Network code master Jeff Garzik points out numerous shortcomings in
- * this driver if it aspires to greatness.
- *
- * Firstly, it doesn't use "NAPI": the networking's New API, and is poorer for
- * it.  As he says "NAPI means system-wide load leveling, across multiple
- * network interfaces.  Lack of NAPI can mean competition at higher loads."
- *
- * He also points out that we don't implement set_mac_address, so users cannot
- * change the devices hardware address.  When I asked why one would want to:
- * "Bonding, and situations where you /do/ want the MAC address to "leak" out
- * of the host onto the wider net."
- *
- * Finally, he would like module unloading: "It is not unrealistic to think of
- * [un|re|]loading the net support module in an lguest guest.  And, adding
- * module support makes the programmer more responsible, because they now have
- * to learn to clean up after themselves.  Any driver that cannot clean up
- * after itself is an incomplete driver in my book."
- :*/
-
-/*D:530 The "struct lguestnet_info" contains all the information we need to
- * know about the network device. */
-struct lguestnet_info
-{
-       /* The mapped device page(s) (an array of "struct lguest_net"). */
-       struct lguest_net *peer;
-       /* The physical address of the device page(s) */
-       unsigned long peer_phys;
-       /* The size of the device page(s). */
-       unsigned long mapsize;
-
-       /* The lguest_device I come from */
-       struct lguest_device *lgdev;
-
-       /* My peerid (ie. my slot in the array). */
-       unsigned int me;
-
-       /* Receive queue: the network packets waiting to be filled. */
-       struct sk_buff *skb[NUM_SKBS];
-       struct lguest_dma dma[NUM_SKBS];
-};
-/*:*/
-
-/* How many bytes left in this page. */
-static unsigned int rest_of_page(void *data)
-{
-       return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
-}
-
-/*D:570 Each peer (ie. Guest or Host) on the network binds their receive
- * buffers to a different key: we simply use the physical address of the
- * device's memory page plus the peer number.  The Host insists that all keys
- * be a multiple of 4, so we multiply the peer number by 4. */
-static unsigned long peer_key(struct lguestnet_info *info, unsigned peernum)
-{
-       return info->peer_phys + 4 * peernum;
-}
-
-/* This is the routine which sets up a "struct lguest_dma" to point to a
- * network packet, similar to req_to_dma() in lguest_blk.c.  The structure of a
- * "struct sk_buff" has grown complex over the years: it consists of a "head"
- * linear section pointed to by "skb->data", and possibly an array of
- * "fragments" in the case of a non-linear packet.
- *
- * Our receive buffers don't use fragments at all but outgoing skbs might, so
- * we handle it. */
-static void skb_to_dma(const struct sk_buff *skb, unsigned int headlen,
-                      struct lguest_dma *dma)
-{
-       unsigned int i, seg;
-
-       /* First, we put the linear region into the "struct lguest_dma".  Each
-        * entry can't go over a page boundary, so even though all our packets
-        * are 1514 bytes or less, we might need to use two entries here: */
-       for (i = seg = 0; i < headlen; seg++, i += rest_of_page(skb->data+i)) {
-               dma->addr[seg] = virt_to_phys(skb->data + i);
-               dma->len[seg] = min((unsigned)(headlen - i),
-                                   rest_of_page(skb->data + i));
-       }
-
-       /* Now we handle the fragments: at least they're guaranteed not to go
-        * over a page.  skb_shinfo(skb) returns a pointer to the structure
-        * which tells us about the number of fragments and the fragment
-        * array. */
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, seg++) {
-               const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
-               /* Should not happen with MTU less than 64k - 2 * PAGE_SIZE. */
-               if (seg == LGUEST_MAX_DMA_SECTIONS) {
-                       /* We will end up sending a truncated packet should
-                        * this ever happen.  Plus, a cool log message! */
-                       printk("Woah dude!  Megapacket!\n");
-                       break;
-               }
-               dma->addr[seg] = page_to_phys(f->page) + f->page_offset;
-               dma->len[seg] = f->size;
-       }
-
-       /* If after all that we didn't use the entire "struct lguest_dma"
-        * array, we terminate it with a 0 length. */
-       if (seg < LGUEST_MAX_DMA_SECTIONS)
-               dma->len[seg] = 0;
-}
-
-/*
- * Packet transmission.
- *
- * Our packet transmission is a little unusual.  A real network card would just
- * send out the packet and leave the receivers to decide if they're interested.
- * Instead, we look through the network device memory page and see if any of
- * the ethernet addresses match the packet destination, and if so we send it to
- * that Guest.
- *
- * This is made a little more complicated in two cases.  The first case is
- * broadcast packets: for that we send the packet to all Guests on the network,
- * one at a time.  The second case is "promiscuous" mode, where a Guest wants
- * to see all the packets on the network.  We need a way for the Guest to tell
- * us it wants to see all packets, so it sets the "multicast" bit on its
- * published MAC address, which is never valid in a real ethernet address.
- */
-#define PROMISC_BIT            0x01
-
-/* This is the callback which is summoned whenever the network device's
- * multicast or promiscuous state changes.  If the card is in promiscuous mode,
- * we advertise that in our ethernet address in the device's memory.  We do the
- * same if Linux wants any or all multicast traffic.  */
-static void lguestnet_set_multicast(struct net_device *dev)
-{
-       struct lguestnet_info *info = netdev_priv(dev);
-
-       if ((dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) || dev->mc_count)
-               info->peer[info->me].mac[0] |= PROMISC_BIT;
-       else
-               info->peer[info->me].mac[0] &= ~PROMISC_BIT;
-}
-
-/* A simple test function to see if a peer wants to see all packets.*/
-static int promisc(struct lguestnet_info *info, unsigned int peer)
-{
-       return info->peer[peer].mac[0] & PROMISC_BIT;
-}
-
-/* Another simple function to see if a peer's advertised ethernet address
- * matches a packet's destination ethernet address. */
-static int mac_eq(const unsigned char mac[ETH_ALEN],
-                 struct lguestnet_info *info, unsigned int peer)
-{
-       /* Ignore multicast bit, which peer turns on to mean promisc. */
-       if ((info->peer[peer].mac[0] & (~PROMISC_BIT)) != mac[0])
-               return 0;
-       return memcmp(mac+1, info->peer[peer].mac+1, ETH_ALEN-1) == 0;
-}
-
-/* This is the function which actually sends a packet once we've decided a
- * peer wants it: */
-static void transfer_packet(struct net_device *dev,
-                           struct sk_buff *skb,
-                           unsigned int peernum)
-{
-       struct lguestnet_info *info = netdev_priv(dev);
-       struct lguest_dma dma;
-
-       /* We use our handy "struct lguest_dma" packing function to prepare
-        * the skb for sending. */
-       skb_to_dma(skb, skb_headlen(skb), &dma);
-       pr_debug("xfer length %04x (%u)\n", htons(skb->len), skb->len);
-
-       /* This is the actual send call which copies the packet. */
-       lguest_send_dma(peer_key(info, peernum), &dma);
-
-       /* Check that the entire packet was transmitted.  If not, it could mean
-        * that the other Guest registered a short receive buffer, but this
-        * driver should never do that.  More likely, the peer is dead. */
-       if (dma.used_len != skb->len) {
-               dev->stats.tx_carrier_errors++;
-               pr_debug("Bad xfer to peer %i: %i of %i (dma %p/%i)\n",
-                        peernum, dma.used_len, skb->len,
-                        (void *)dma.addr[0], dma.len[0]);
-       } else {
-               /* On success we update the stats. */
-               dev->stats.tx_bytes += skb->len;
-               dev->stats.tx_packets++;
-       }
-}
-
-/* Another helper function to tell is if a slot in the device memory is unused.
- * Since we always set the Local Assignment bit in the ethernet address, the
- * first byte can never be 0. */
-static int unused_peer(const struct lguest_net peer[], unsigned int num)
-{
-       return peer[num].mac[0] == 0;
-}
-
-/* Finally, here is the routine which handles an outgoing packet.  It's called
- * "start_xmit" for traditional reasons. */
-static int lguestnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       unsigned int i;
-       int broadcast;
-       struct lguestnet_info *info = netdev_priv(dev);
-       /* Extract the destination ethernet address from the packet. */
-       const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
-       DECLARE_MAC_BUF(mac);
-
-       pr_debug("%s: xmit %s\n", dev->name, print_mac(mac, dest));
-
-       /* If it's a multicast packet, we broadcast to everyone.  That's not
-        * very efficient, but there are very few applications which actually
-        * use multicast, which is a shame really.
-        *
-        * As etherdevice.h points out: "By definition the broadcast address is
-        * also a multicast address."  So we don't have to test for broadcast
-        * packets separately. */
-       broadcast = is_multicast_ether_addr(dest);
-
-       /* Look through all the published ethernet addresses to see if we
-        * should send this packet. */
-       for (i = 0; i < info->mapsize/sizeof(struct lguest_net); i++) {
-               /* We don't send to ourselves (we actually can't SEND_DMA to
-                * ourselves anyway), and don't send to unused slots.*/
-               if (i == info->me || unused_peer(info->peer, i))
-                       continue;
-
-               /* If it's broadcast we send it.  If they want every packet we
-                * send it.  If the destination matches their address we send
-                * it.  Otherwise we go to the next peer. */
-               if (!broadcast && !promisc(info, i) && !mac_eq(dest, info, i))
-                       continue;
-
-               pr_debug("lguestnet %s: sending from %i to %i\n",
-                        dev->name, info->me, i);
-               /* Our routine which actually does the transfer. */
-               transfer_packet(dev, skb, i);
-       }
-
-       /* An xmit routine is expected to dispose of the packet, so we do. */
-       dev_kfree_skb(skb);
-
-       /* As per kernel convention, 0 means success.  This is why I love
-        * networking: even if we never sent to anyone, that's still
-        * success! */
-       return 0;
-}
-
-/*D:560
- * Packet receiving.
- *
- * First, here's a helper routine which fills one of our array of receive
- * buffers: */
-static int fill_slot(struct net_device *dev, unsigned int slot)
-{
-       struct lguestnet_info *info = netdev_priv(dev);
-
-       /* We can receive ETH_DATA_LEN (1500) byte packets, plus a standard
-        * ethernet header of ETH_HLEN (14) bytes. */
-       info->skb[slot] = netdev_alloc_skb(dev, ETH_HLEN + ETH_DATA_LEN);
-       if (!info->skb[slot]) {
-               printk("%s: could not fill slot %i\n", dev->name, slot);
-               return -ENOMEM;
-       }
-
-       /* skb_to_dma() is a helper which sets up the "struct lguest_dma" to
-        * point to the data in the skb: we also use it for sending out a
-        * packet. */
-       skb_to_dma(info->skb[slot], ETH_HLEN + ETH_DATA_LEN, &info->dma[slot]);
-
-       /* This is a Write Memory Barrier: it ensures that the entry in the
-        * receive buffer array is written *before* we set the "used_len" entry
-        * to 0.  If the Host were looking at the receive buffer array from a
-        * different CPU, it could potentially see "used_len = 0" and not see
-        * the updated receive buffer information.  This would be a horribly
-        * nasty bug, so make sure the compiler and CPU know this has to happen
-        * first. */
-       wmb();
-       /* Writing 0 to "used_len" tells the Host it can use this receive
-        * buffer now. */
-       info->dma[slot].used_len = 0;
-       return 0;
-}
-
-/* This is the actual receive routine.  When we receive an interrupt from the
- * Host to tell us a packet has been delivered, we arrive here: */
-static irqreturn_t lguestnet_rcv(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct lguestnet_info *info = netdev_priv(dev);
-       unsigned int i, done = 0;
-
-       /* Look through our entire receive array for an entry which has data
-        * in it. */
-       for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
-               unsigned int length;
-               struct sk_buff *skb;
-
-               length = info->dma[i].used_len;
-               if (length == 0)
-                       continue;
-
-               /* We've found one!  Remember the skb (we grabbed the length
-                * above), and immediately refill the slot we've taken it
-                * from. */
-               done++;
-               skb = info->skb[i];
-               fill_slot(dev, i);
-
-               /* This shouldn't happen: micropackets could be sent by a
-                * badly-behaved Guest on the network, but the Host will never
-                * stuff more data in the buffer than the buffer length. */
-               if (length < ETH_HLEN || length > ETH_HLEN + ETH_DATA_LEN) {
-                       pr_debug(KERN_WARNING "%s: unbelievable skb len: %i\n",
-                                dev->name, length);
-                       dev_kfree_skb(skb);
-                       continue;
-               }
-
-               /* skb_put(), what a great function!  I've ranted about this
-                * function before (http://lkml.org/lkml/1999/9/26/24).  You
-                * call it after you've added data to the end of an skb (in
-                * this case, it was the Host which wrote the data). */
-               skb_put(skb, length);
-
-               /* The ethernet header contains a protocol field: we use the
-                * standard helper to extract it, and place the result in
-                * skb->protocol.  The helper also sets up skb->pkt_type and
-                * eats up the ethernet header from the front of the packet. */
-               skb->protocol = eth_type_trans(skb, dev);
-
-               /* If this device doesn't need checksums for sending, we also
-                * don't need to check the packets when they come in. */
-               if (dev->features & NETIF_F_NO_CSUM)
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-               /* As a last resort for debugging the driver or the lguest I/O
-                * subsystem, you can uncomment the "#define DEBUG" at the top
-                * of this file, which turns all the pr_debug() into printk()
-                * and floods the logs. */
-               pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
-                        ntohs(skb->protocol), skb->len, skb->pkt_type);
-
-               /* Update the packet and byte counts (visible from ifconfig,
-                * and good for debugging). */
-               dev->stats.rx_bytes += skb->len;
-               dev->stats.rx_packets++;
-
-               /* Hand our fresh network packet into the stack's "network
-                * interface receive" routine.  That will free the packet
-                * itself when it's finished. */
-               netif_rx(skb);
-       }
-
-       /* If we found any packets, we assume the interrupt was for us. */
-       return done ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/*D:550 This is where we start: when the device is brought up by dhcpd or
- * ifconfig.  At this point we advertise our MAC address to the rest of the
- * network, and register receive buffers ready for incoming packets. */
-static int lguestnet_open(struct net_device *dev)
-{
-       int i;
-       struct lguestnet_info *info = netdev_priv(dev);
-
-       /* Copy our MAC address into the device page, so others on the network
-        * can find us. */
-       memcpy(info->peer[info->me].mac, dev->dev_addr, ETH_ALEN);
-
-       /* We might already be in promisc mode (dev->flags & IFF_PROMISC).  Our
-        * set_multicast callback handles this already, so we call it now. */
-       lguestnet_set_multicast(dev);
-
-       /* Allocate packets and put them into our "struct lguest_dma" array.
-        * If we fail to allocate all the packets we could still limp along,
-        * but it's a sign of real stress so we should probably give up now. */
-       for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
-               if (fill_slot(dev, i) != 0)
-                       goto cleanup;
-       }
-
-       /* Finally we tell the Host where our array of "struct lguest_dma"
-        * receive buffers is, binding it to the key corresponding to the
-        * device's physical memory plus our peerid. */
-       if (lguest_bind_dma(peer_key(info,info->me), info->dma,
-                           NUM_SKBS, lgdev_irq(info->lgdev)) != 0)
-               goto cleanup;
-       return 0;
-
-cleanup:
-       while (--i >= 0)
-               dev_kfree_skb(info->skb[i]);
-       return -ENOMEM;
-}
-/*:*/
-
-/* The close routine is called when the device is no longer in use: we clean up
- * elegantly. */
-static int lguestnet_close(struct net_device *dev)
-{
-       unsigned int i;
-       struct lguestnet_info *info = netdev_priv(dev);
-
-       /* Clear all trace of our existence out of the device memory by setting
-        * the slot which held our MAC address to 0 (unused). */
-       memset(&info->peer[info->me], 0, sizeof(info->peer[info->me]));
-
-       /* Unregister our array of receive buffers */
-       lguest_unbind_dma(peer_key(info, info->me), info->dma);
-       for (i = 0; i < ARRAY_SIZE(info->dma); i++)
-               dev_kfree_skb(info->skb[i]);
-       return 0;
-}
-
-/*D:510 The network device probe function is basically a standard ethernet
- * device setup.  It reads the "struct lguest_device_desc" and sets the "struct
- * net_device".  Oh, the line-by-line excitement!  Let's skip over it. :*/
-static int lguestnet_probe(struct lguest_device *lgdev)
-{
-       int err, irqf = IRQF_SHARED;
-       struct net_device *dev;
-       struct lguestnet_info *info;
-       struct lguest_device_desc *desc = &lguest_devices[lgdev->index];
-
-       pr_debug("lguest_net: probing for device %i\n", lgdev->index);
-
-       dev = alloc_etherdev(sizeof(struct lguestnet_info));
-       if (!dev)
-               return -ENOMEM;
-
-       /* Ethernet defaults with some changes */
-       ether_setup(dev);
-       dev->set_mac_address = NULL;
-
-       dev->dev_addr[0] = 0x02; /* set local assignment bit (IEEE802) */
-       dev->dev_addr[1] = 0x00;
-       memcpy(&dev->dev_addr[2], &lguest_data.guestid, 2);
-       dev->dev_addr[4] = 0x00;
-       dev->dev_addr[5] = 0x00;
-
-       dev->open = lguestnet_open;
-       dev->stop = lguestnet_close;
-       dev->hard_start_xmit = lguestnet_start_xmit;
-
-       /* We don't actually support multicast yet, but turning on/off
-        * promisc also calls dev->set_multicast_list. */
-       dev->set_multicast_list = lguestnet_set_multicast;
-       SET_NETDEV_DEV(dev, &lgdev->dev);
-
-       /* The network code complains if you have "scatter-gather" capability
-        * if you don't also handle checksums (it seem that would be
-        * "illogical").  So we use a lie of omission and don't tell it that we
-        * can handle scattered packets unless we also don't want checksums,
-        * even though to us they're completely independent. */
-       if (desc->features & LGUEST_NET_F_NOCSUM)
-               dev->features = NETIF_F_SG|NETIF_F_NO_CSUM;
-
-       info = netdev_priv(dev);
-       info->mapsize = PAGE_SIZE * desc->num_pages;
-       info->peer_phys = ((unsigned long)desc->pfn << PAGE_SHIFT);
-       info->lgdev = lgdev;
-       info->peer = lguest_map(info->peer_phys, desc->num_pages);
-       if (!info->peer) {
-               err = -ENOMEM;
-               goto free;
-       }
-
-       /* This stores our peerid (upper bits reserved for future). */
-       info->me = (desc->features & (info->mapsize-1));
-
-       err = register_netdev(dev);
-       if (err) {
-               pr_debug("lguestnet: registering device failed\n");
-               goto unmap;
-       }
-
-       if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
-               irqf |= IRQF_SAMPLE_RANDOM;
-       if (request_irq(lgdev_irq(lgdev), lguestnet_rcv, irqf, "lguestnet",
-                       dev) != 0) {
-               pr_debug("lguestnet: cannot get irq %i\n", lgdev_irq(lgdev));
-               goto unregister;
-       }
-
-       pr_debug("lguestnet: registered device %s\n", dev->name);
-       /* Finally, we put the "struct net_device" in the generic "struct
-        * lguest_device"s private pointer.  Again, it's not necessary, but
-        * makes sure the cool kernel kids don't tease us. */
-       lgdev->private = dev;
-       return 0;
-
-unregister:
-       unregister_netdev(dev);
-unmap:
-       lguest_unmap(info->peer);
-free:
-       free_netdev(dev);
-       return err;
-}
-
-static struct lguest_driver lguestnet_drv = {
-       .name = "lguestnet",
-       .owner = THIS_MODULE,
-       .device_type = LGUEST_DEVICE_T_NET,
-       .probe = lguestnet_probe,
-};
-
-static __init int lguestnet_init(void)
-{
-       return register_lguest_driver(&lguestnet_drv);
-}
-module_init(lguestnet_init);
-
-MODULE_DESCRIPTION("Lguest network driver");
-MODULE_LICENSE("GPL");
-
-/*D:580
- * This is the last of the Drivers, and with this we have covered the many and
- * wonderous and fine (and boring) details of the Guest.
- *
- * "make Launcher" beckons, where we answer questions like "Where do Guests
- * come from?", and "What do you do when someone asks for optimization?"
- */
index 6471d33..5064873 100644 (file)
@@ -736,7 +736,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
        MLX4_PUT(inbox, (u8) (PAGE_SHIFT - 12), INIT_HCA_UAR_PAGE_SZ_OFFSET);
        MLX4_PUT(inbox, param->log_uar_sz,      INIT_HCA_LOG_UAR_SZ_OFFSET);
 
-       err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 1000);
+       err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000);
 
        if (err)
                mlx4_err(dev, "INIT_HCA returns %d\n", err);
index 4b3c109..887633b 100644 (file)
@@ -60,7 +60,7 @@ static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chu
                             PCI_DMA_BIDIRECTIONAL);
 
        for (i = 0; i < chunk->npages; ++i)
-               __free_pages(chunk->mem[i].page,
+               __free_pages(sg_page(&chunk->mem[i]),
                             get_order(chunk->mem[i].length));
 }
 
@@ -70,7 +70,7 @@ static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *
 
        for (i = 0; i < chunk->npages; ++i)
                dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
-                                 lowmem_page_address(chunk->mem[i].page),
+                                 lowmem_page_address(sg_page(&chunk->mem[i])),
                                  sg_dma_address(&chunk->mem[i]));
 }
 
@@ -95,10 +95,13 @@ void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent)
 
 static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
 {
-       mem->page = alloc_pages(gfp_mask, order);
-       if (!mem->page)
+       struct page *page;
+
+       page = alloc_pages(gfp_mask, order);
+       if (!page)
                return -ENOMEM;
 
+       sg_set_page(mem, page);
        mem->length = PAGE_SIZE << order;
        mem->offset = 0;
        return 0;
@@ -145,6 +148,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
                        if (!chunk)
                                goto fail;
 
+                       sg_init_table(chunk->mem, MLX4_ICM_CHUNK_LEN);
                        chunk->npages = 0;
                        chunk->nsg    = 0;
                        list_add_tail(&chunk->list, &icm->chunk_list);
@@ -334,7 +338,7 @@ void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_han
                         * been assigned to.
                         */
                        if (chunk->mem[i].length > offset) {
-                               page = chunk->mem[i].page;
+                               page = sg_page(&chunk->mem[i]);
                                goto out;
                        }
                        offset -= chunk->mem[i].length;
index ed1f9bb..112ab07 100644 (file)
@@ -3103,31 +3103,12 @@ static int niu_alloc_tx_ring_info(struct niu *np,
 
 static void niu_size_rbr(struct niu *np, struct rx_ring_info *rp)
 {
-       u16 bs;
+       u16 bss;
 
-       switch (PAGE_SIZE) {
-       case 4 * 1024:
-       case 8 * 1024:
-       case 16 * 1024:
-       case 32 * 1024:
-               rp->rbr_block_size = PAGE_SIZE;
-               rp->rbr_blocks_per_page = 1;
-               break;
+       bss = min(PAGE_SHIFT, 15);
 
-       default:
-               if (PAGE_SIZE % (32 * 1024) == 0)
-                       bs = 32 * 1024;
-               else if (PAGE_SIZE % (16 * 1024) == 0)
-                       bs = 16 * 1024;
-               else if (PAGE_SIZE % (8 * 1024) == 0)
-                       bs = 8 * 1024;
-               else if (PAGE_SIZE % (4 * 1024) == 0)
-                       bs = 4 * 1024;
-               else
-                       BUG();
-               rp->rbr_block_size = bs;
-               rp->rbr_blocks_per_page = PAGE_SIZE / bs;
-       }
+       rp->rbr_block_size = 1 << bss;
+       rp->rbr_blocks_per_page = 1 << (PAGE_SHIFT-bss);
 
        rp->rbr_sizes[0] = 256;
        rp->rbr_sizes[1] = 1024;
@@ -7902,12 +7883,7 @@ static int __init niu_init(void)
 {
        int err = 0;
 
-       BUILD_BUG_ON((PAGE_SIZE < 4 * 1024) ||
-                    ((PAGE_SIZE > 32 * 1024) &&
-                     ((PAGE_SIZE % (32 * 1024)) != 0 &&
-                      (PAGE_SIZE % (16 * 1024)) != 0 &&
-                      (PAGE_SIZE % (8 * 1024)) != 0 &&
-                      (PAGE_SIZE % (4 * 1024)) != 0)));
+       BUILD_BUG_ON(PAGE_SIZE < 4 * 1024);
 
        niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT);
 
index c0b6d19..bcb0885 100644 (file)
@@ -55,7 +55,7 @@
 #include <linux/mm.h>
 #include <linux/ppp_defs.h>
 #include <linux/ppp-comp.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 #include "ppp_mppe.h"
 
@@ -68,9 +68,7 @@ MODULE_VERSION("1.0.2");
 static unsigned int
 setup_sg(struct scatterlist *sg, const void *address, unsigned int length)
 {
-       sg[0].page = virt_to_page(address);
-       sg[0].offset = offset_in_page(address);
-       sg[0].length = length;
+       sg_init_one(sg, address, length);
        return length;
 }
 
index 419c00c..e8960f2 100644 (file)
@@ -44,7 +44,8 @@
                printk( "Assertion failed! %s,%s,%s,line=%d\n", \
                #expr,__FILE__,__FUNCTION__,__LINE__);          \
        }
-#define dprintk(fmt, args...)  do { printk(PFX fmt, ## args); } while (0)
+#define dprintk(fmt, args...) \
+       do { printk(KERN_DEBUG PFX fmt, ## args); } while (0)
 #else
 #define assert(expr) do {} while (0)
 #define dprintk(fmt, args...)  do {} while (0)
@@ -111,19 +112,15 @@ enum mac_version {
        RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
        RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
        RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
-       RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be 8168Bf
-       RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb 8101Ec
-       RTL_GIGA_MAC_VER_14 = 0x0e, // 8101
-       RTL_GIGA_MAC_VER_15 = 0x0f  // 8101
-};
-
-enum phy_version {
-       RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */
-       RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */
-       RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */
-       RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */
-       RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */
-       RTL_GIGA_PHY_VER_H = 0x08, /* PHY Reg 0x03 bit0-3 == 0x0003 */
+       RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
+       RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
+       RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
+       RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
+       RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
+       RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
+       RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
+       RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
+       RTL_GIGA_MAC_VER_20 = 0x14  // 8168C
 };
 
 #define _R(NAME,MAC,MASK) \
@@ -144,7 +141,12 @@ static const struct {
        _R("RTL8168b/8111b",    RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
        _R("RTL8101e",          RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
        _R("RTL8100e",          RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
-       _R("RTL8100e",          RTL_GIGA_MAC_VER_15, 0xff7e1880)  // PCI-E 8139
+       _R("RTL8100e",          RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139
+       _R("RTL8168b/8111b",    RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E
+       _R("RTL8101e",          RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E
+       _R("RTL8168cp/8111cp",  RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E
+       _R("RTL8168c/8111c",    RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E
+       _R("RTL8168c/8111c",    RTL_GIGA_MAC_VER_20, 0xff7e1880)  // PCI-E
 };
 #undef _R
 
@@ -165,7 +167,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8168), 0, 0, RTL_CFG_1 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8169), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK,       0x4300), 0, 0, RTL_CFG_0 },
-       { PCI_DEVICE(0x1259,                    0xc107), 0, 0, RTL_CFG_0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_AT,          0xc107), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(0x16ec,                    0x0116), 0, 0, RTL_CFG_0 },
        { PCI_VENDOR_ID_LINKSYS,                0x1032,
                PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
@@ -277,6 +279,7 @@ enum rtl_register_content {
        TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
 
        /* Config1 register p.24 */
+       MSIEnable       = (1 << 5),     /* Enable Message Signaled Interrupt */
        PMEnable        = (1 << 0),     /* Power Management Enable */
 
        /* Config2 register p. 25 */
@@ -380,17 +383,20 @@ struct ring_info {
        u8              __pad[sizeof(void *) - sizeof(u32)];
 };
 
+enum features {
+       RTL_FEATURE_WOL = (1 << 0),
+       RTL_FEATURE_MSI = (1 << 1),
+};
+
 struct rtl8169_private {
        void __iomem *mmio_addr;        /* memory map physical address */
        struct pci_dev *pci_dev;        /* Index of PCI device */
        struct net_device *dev;
        struct napi_struct napi;
-       struct net_device_stats stats;  /* statistics of net device */
        spinlock_t lock;                /* spin lock flag */
        u32 msg_enable;
        int chipset;
        int mac_version;
-       int phy_version;
        u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
        u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
        u32 dirty_rx;
@@ -420,7 +426,7 @@ struct rtl8169_private {
        unsigned int (*phy_reset_pending)(void __iomem *);
        unsigned int (*link_ok)(void __iomem *);
        struct delayed_work task;
-       unsigned wol_enabled : 1;
+       unsigned features;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -626,7 +632,10 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
        RTL_W8(Cfg9346, Cfg9346_Lock);
 
-       tp->wol_enabled = (wol->wolopts) ? 1 : 0;
+       if (wol->wolopts)
+               tp->features |= RTL_FEATURE_WOL;
+       else
+               tp->features &= ~RTL_FEATURE_WOL;
 
        spin_unlock_irq(&tp->lock);
 
@@ -707,7 +716,8 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
 
                /* This tweak comes straight from Realtek's driver. */
                if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
-                   (tp->mac_version == RTL_GIGA_MAC_VER_13)) {
+                   ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+                    (tp->mac_version == RTL_GIGA_MAC_VER_16))) {
                        auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
                }
        }
@@ -715,7 +725,8 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
        /* The 8100e/8101e do Fast Ethernet only. */
        if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
+           (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
                if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
                    netif_msg_link(tp)) {
                        printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n",
@@ -726,7 +737,8 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
 
        auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_12) {
+       if ((tp->mac_version == RTL_GIGA_MAC_VER_12) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_17)) {
                /* Vendor specific (0x1f) and reserved (0x0e) MII registers. */
                mdio_write(ioaddr, 0x1f, 0x0000);
                mdio_write(ioaddr, 0x0e, 0x0000);
@@ -1104,26 +1116,51 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
         */
        const struct {
                u32 mask;
+               u32 val;
                int mac_version;
        } mac_info[] = {
-               { 0x38800000,   RTL_GIGA_MAC_VER_15 },
-               { 0x38000000,   RTL_GIGA_MAC_VER_12 },
-               { 0x34000000,   RTL_GIGA_MAC_VER_13 },
-               { 0x30800000,   RTL_GIGA_MAC_VER_14 },
-               { 0x30000000,   RTL_GIGA_MAC_VER_11 },
-               { 0x98000000,   RTL_GIGA_MAC_VER_06 },
-               { 0x18000000,   RTL_GIGA_MAC_VER_05 },
-               { 0x10000000,   RTL_GIGA_MAC_VER_04 },
-               { 0x04000000,   RTL_GIGA_MAC_VER_03 },
-               { 0x00800000,   RTL_GIGA_MAC_VER_02 },
-               { 0x00000000,   RTL_GIGA_MAC_VER_01 }   /* Catch-all */
+               /* 8168B family. */
+               { 0x7c800000, 0x3c800000,       RTL_GIGA_MAC_VER_18 },
+               { 0x7cf00000, 0x3c000000,       RTL_GIGA_MAC_VER_19 },
+               { 0x7cf00000, 0x3c200000,       RTL_GIGA_MAC_VER_20 },
+               { 0x7c800000, 0x3c000000,       RTL_GIGA_MAC_VER_20 },
+
+               /* 8168B family. */
+               { 0x7cf00000, 0x38000000,       RTL_GIGA_MAC_VER_12 },
+               { 0x7cf00000, 0x38500000,       RTL_GIGA_MAC_VER_17 },
+               { 0x7c800000, 0x38000000,       RTL_GIGA_MAC_VER_17 },
+               { 0x7c800000, 0x30000000,       RTL_GIGA_MAC_VER_11 },
+
+               /* 8101 family. */
+               { 0x7cf00000, 0x34000000,       RTL_GIGA_MAC_VER_13 },
+               { 0x7cf00000, 0x34200000,       RTL_GIGA_MAC_VER_16 },
+               { 0x7c800000, 0x34000000,       RTL_GIGA_MAC_VER_16 },
+               /* FIXME: where did these entries come from ? -- FR */
+               { 0xfc800000, 0x38800000,       RTL_GIGA_MAC_VER_15 },
+               { 0xfc800000, 0x30800000,       RTL_GIGA_MAC_VER_14 },
+
+               /* 8110 family. */
+               { 0xfc800000, 0x98000000,       RTL_GIGA_MAC_VER_06 },
+               { 0xfc800000, 0x18000000,       RTL_GIGA_MAC_VER_05 },
+               { 0xfc800000, 0x10000000,       RTL_GIGA_MAC_VER_04 },
+               { 0xfc800000, 0x04000000,       RTL_GIGA_MAC_VER_03 },
+               { 0xfc800000, 0x00800000,       RTL_GIGA_MAC_VER_02 },
+               { 0xfc800000, 0x00000000,       RTL_GIGA_MAC_VER_01 },
+
+               { 0x00000000, 0x00000000,       RTL_GIGA_MAC_VER_01 }   /* Catch-all */
        }, *p = mac_info;
        u32 reg;
 
-       reg = RTL_R32(TxConfig) & 0xfc800000;
-       while ((reg & p->mask) != p->mask)
+       reg = RTL_R32(TxConfig);
+       while ((reg & p->mask) != p->val)
                p++;
        tp->mac_version = p->mac_version;
+
+       if (p->mask == 0x00000000) {
+               struct pci_dev *pdev = tp->pci_dev;
+
+               dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg);
+       }
 }
 
 static void rtl8169_print_mac_version(struct rtl8169_private *tp)
@@ -1131,54 +1168,21 @@ static void rtl8169_print_mac_version(struct rtl8169_private *tp)
        dprintk("mac_version = 0x%02x\n", tp->mac_version);
 }
 
-static void rtl8169_get_phy_version(struct rtl8169_private *tp,
-                                   void __iomem *ioaddr)
-{
-       const struct {
-               u16 mask;
-               u16 set;
-               int phy_version;
-       } phy_info[] = {
-               { 0x000f, 0x0002, RTL_GIGA_PHY_VER_G },
-               { 0x000f, 0x0001, RTL_GIGA_PHY_VER_F },
-               { 0x000f, 0x0000, RTL_GIGA_PHY_VER_E },
-               { 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */
-       }, *p = phy_info;
+struct phy_reg {
        u16 reg;
+       u16 val;
+};
 
-       reg = mdio_read(ioaddr, MII_PHYSID2) & 0xffff;
-       while ((reg & p->mask) != p->set)
-               p++;
-       tp->phy_version = p->phy_version;
-}
-
-static void rtl8169_print_phy_version(struct rtl8169_private *tp)
+static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len)
 {
-       struct {
-               int version;
-               char *msg;
-               u32 reg;
-       } phy_print[] = {
-               { RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 },
-               { RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 },
-               { RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 },
-               { RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 },
-               { 0, NULL, 0x0000 }
-       }, *p;
-
-       for (p = phy_print; p->msg; p++) {
-               if (tp->phy_version == p->version) {
-                       dprintk("phy_version == %s (%04x)\n", p->msg, p->reg);
-                       return;
-               }
+       while (len-- > 0) {
+               mdio_write(ioaddr, regs->reg, regs->val);
+               regs++;
        }
-       dprintk("phy_version == Unknown\n");
 }
 
-static void rtl8169_hw_phy_config(struct net_device *dev)
+static void rtl8169s_hw_phy_config(void __iomem *ioaddr)
 {
-       struct rtl8169_private *tp = netdev_priv(dev);
-       void __iomem *ioaddr = tp->mmio_addr;
        struct {
                u16 regs[5]; /* Beware of bit-sign propagation */
        } phy_magic[5] = { {
@@ -1211,33 +1215,9 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
        }, *p = phy_magic;
        unsigned int i;
 
-       rtl8169_print_mac_version(tp);
-       rtl8169_print_phy_version(tp);
-
-       if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
-               return;
-       if (tp->phy_version >= RTL_GIGA_PHY_VER_H)
-               return;
-
-       dprintk("MAC version != 0 && PHY version == 0 or 1\n");
-       dprintk("Do final_reg2.cfg\n");
-
-       /* Shazam ! */
-
-       if (tp->mac_version == RTL_GIGA_MAC_VER_04) {
-               mdio_write(ioaddr, 31, 0x0002);
-               mdio_write(ioaddr,  1, 0x90d0);
-               mdio_write(ioaddr, 31, 0x0000);
-               return;
-       }
-
-       if ((tp->mac_version != RTL_GIGA_MAC_VER_02) &&
-           (tp->mac_version != RTL_GIGA_MAC_VER_03))
-               return;
-
-       mdio_write(ioaddr, 31, 0x0001);                 //w 31 2 0 1
-       mdio_write(ioaddr, 21, 0x1000);                 //w 21 15 0 1000
-       mdio_write(ioaddr, 24, 0x65c7);                 //w 24 15 0 65c7
+       mdio_write(ioaddr, 0x1f, 0x0001);               //w 31 2 0 1
+       mdio_write(ioaddr, 0x15, 0x1000);               //w 21 15 0 1000
+       mdio_write(ioaddr, 0x18, 0x65c7);               //w 24 15 0 65c7
        rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0);   //w 4 11 11 0
 
        for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
@@ -1250,7 +1230,115 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
                rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
                rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
        }
-       mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0
+       mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
+}
+
+static void rtl8169sb_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0002 },
+               { 0x01, 0x90d0 },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+static void rtl8168b_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0000 },
+               { 0x10, 0xf41b },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0000 },
+               { 0x1d, 0x0f00 },
+               { 0x1f, 0x0002 },
+               { 0x0c, 0x1ec8 },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168c_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0001 },
+               { 0x12, 0x2300 },
+               { 0x1f, 0x0002 },
+               { 0x00, 0x88d4 },
+               { 0x01, 0x82b1 },
+               { 0x03, 0x7002 },
+               { 0x08, 0x9e30 },
+               { 0x09, 0x01f0 },
+               { 0x0a, 0x5500 },
+               { 0x0c, 0x00c8 },
+               { 0x1f, 0x0003 },
+               { 0x12, 0xc096 },
+               { 0x16, 0x000a },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cx_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0000 },
+               { 0x12, 0x2300 },
+               { 0x1f, 0x0003 },
+               { 0x16, 0x0f0a },
+               { 0x1f, 0x0000 },
+               { 0x1f, 0x0002 },
+               { 0x0c, 0x7eb8 },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl_hw_phy_config(struct net_device *dev)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       rtl8169_print_mac_version(tp);
+
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_01:
+               break;
+       case RTL_GIGA_MAC_VER_02:
+       case RTL_GIGA_MAC_VER_03:
+               rtl8169s_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_04:
+               rtl8169sb_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_11:
+       case RTL_GIGA_MAC_VER_12:
+       case RTL_GIGA_MAC_VER_17:
+               rtl8168b_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_18:
+               rtl8168cp_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_19:
+               rtl8168c_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_20:
+               rtl8168cx_hw_phy_config(ioaddr);
+               break;
+       default:
+               break;
+       }
 }
 
 static void rtl8169_phy_timer(unsigned long __opaque)
@@ -1262,7 +1350,6 @@ static void rtl8169_phy_timer(unsigned long __opaque)
        unsigned long timeout = RTL8169_PHY_TIMEOUT;
 
        assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
-       assert(tp->phy_version < RTL_GIGA_PHY_VER_H);
 
        if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
                return;
@@ -1297,8 +1384,7 @@ static inline void rtl8169_delete_timer(struct net_device *dev)
        struct rtl8169_private *tp = netdev_priv(dev);
        struct timer_list *timer = &tp->timer;
 
-       if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
-           (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+       if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
                return;
 
        del_timer_sync(timer);
@@ -1309,8 +1395,7 @@ static inline void rtl8169_request_timer(struct net_device *dev)
        struct rtl8169_private *tp = netdev_priv(dev);
        struct timer_list *timer = &tp->timer;
 
-       if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
-           (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+       if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
                return;
 
        mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);
@@ -1362,7 +1447,7 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
 
-       rtl8169_hw_phy_config(dev);
+       rtl_hw_phy_config(dev);
 
        dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
        RTL_W8(0x82, 0x01);
@@ -1457,6 +1542,7 @@ static const struct rtl_cfg_info {
        unsigned int align;
        u16 intr_event;
        u16 napi_event;
+       unsigned msi;
 } rtl_cfg_infos [] = {
        [RTL_CFG_0] = {
                .hw_start       = rtl_hw_start_8169,
@@ -1464,7 +1550,8 @@ static const struct rtl_cfg_info {
                .align          = 0,
                .intr_event     = SYSErr | LinkChg | RxOverflow |
                                  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
-               .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow
+               .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+               .msi            = 0
        },
        [RTL_CFG_1] = {
                .hw_start       = rtl_hw_start_8168,
@@ -1472,7 +1559,8 @@ static const struct rtl_cfg_info {
                .align          = 8,
                .intr_event     = SYSErr | LinkChg | RxOverflow |
                                  TxErr | TxOK | RxOK | RxErr,
-               .napi_event     = TxErr | TxOK | RxOK | RxOverflow
+               .napi_event     = TxErr | TxOK | RxOK | RxOverflow,
+               .msi            = RTL_FEATURE_MSI
        },
        [RTL_CFG_2] = {
                .hw_start       = rtl_hw_start_8101,
@@ -1480,10 +1568,39 @@ static const struct rtl_cfg_info {
                .align          = 8,
                .intr_event     = SYSErr | LinkChg | RxOverflow | PCSTimeout |
                                  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
-               .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow
+               .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+               .msi            = RTL_FEATURE_MSI
        }
 };
 
+/* Cfg9346_Unlock assumed. */
+static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr,
+                           const struct rtl_cfg_info *cfg)
+{
+       unsigned msi = 0;
+       u8 cfg2;
+
+       cfg2 = RTL_R8(Config2) & ~MSIEnable;
+       if (cfg->msi) {
+               if (pci_enable_msi(pdev)) {
+                       dev_info(&pdev->dev, "no MSI. Back to INTx.\n");
+               } else {
+                       cfg2 |= MSIEnable;
+                       msi = RTL_FEATURE_MSI;
+               }
+       }
+       RTL_W8(Config2, cfg2);
+       return msi;
+}
+
+static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
+{
+       if (tp->features & RTL_FEATURE_MSI) {
+               pci_disable_msi(pdev);
+               tp->features &= ~RTL_FEATURE_MSI;
+       }
+}
+
 static int __devinit
 rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -1596,10 +1713,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* Identify chip attached to board */
        rtl8169_get_mac_version(tp, ioaddr);
-       rtl8169_get_phy_version(tp, ioaddr);
 
        rtl8169_print_mac_version(tp);
-       rtl8169_print_phy_version(tp);
 
        for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
                if (tp->mac_version == rtl_chip_info[i].mac_version)
@@ -1619,6 +1734,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        RTL_W8(Cfg9346, Cfg9346_Unlock);
        RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
        RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
+       tp->features |= rtl_try_msi(pdev, ioaddr, cfg);
        RTL_W8(Cfg9346, Cfg9346_Lock);
 
        if (RTL_R8(PHYstatus) & TBI_Enable) {
@@ -1686,7 +1802,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        rc = register_netdev(dev);
        if (rc < 0)
-               goto err_out_unmap_5;
+               goto err_out_msi_5;
 
        pci_set_drvdata(pdev, dev);
 
@@ -1709,7 +1825,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 out:
        return rc;
 
-err_out_unmap_5:
+err_out_msi_5:
+       rtl_disable_msi(pdev, tp);
        iounmap(ioaddr);
 err_out_free_res_4:
        pci_release_regions(pdev);
@@ -1730,6 +1847,7 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
        flush_scheduled_work();
 
        unregister_netdev(dev);
+       rtl_disable_msi(pdev, tp);
        rtl8169_release_board(pdev, dev, tp->mmio_addr);
        pci_set_drvdata(pdev, NULL);
 }
@@ -1773,7 +1891,8 @@ static int rtl8169_open(struct net_device *dev)
 
        smp_mb();
 
-       retval = request_irq(dev->irq, rtl8169_interrupt, IRQF_SHARED,
+       retval = request_irq(dev->irq, rtl8169_interrupt,
+                            (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
                             dev->name, dev);
        if (retval < 0)
                goto err_release_ring_2;
@@ -1933,7 +2052,7 @@ static void rtl_hw_start_8169(struct net_device *dev)
 
        if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
-               dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. "
+               dprintk("Set MAC Reg C+CR Offset 0xE0. "
                        "Bit-3 and bit-14 MUST be 1\n");
                tp->cp_cmd |= (1 << 14);
        }
@@ -2029,7 +2148,8 @@ static void rtl_hw_start_8101(struct net_device *dev)
        void __iomem *ioaddr = tp->mmio_addr;
        struct pci_dev *pdev = tp->pci_dev;
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
+       if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
                pci_write_config_word(pdev, 0x68, 0x00);
                pci_write_config_word(pdev, 0x69, 0x08);
        }
@@ -2259,7 +2379,7 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp)
                                dev_kfree_skb(skb);
                                tx_skb->skb = NULL;
                        }
-                       tp->stats.tx_dropped++;
+                       tp->dev->stats.tx_dropped++;
                }
        }
        tp->cur_tx = tp->dirty_tx = 0;
@@ -2310,7 +2430,7 @@ static void rtl8169_reinit_task(struct work_struct *work)
        ret = rtl8169_open(dev);
        if (unlikely(ret < 0)) {
                if (net_ratelimit() && netif_msg_drv(tp)) {
-                       printk(PFX KERN_ERR "%s: reinit failure (status = %d)."
+                       printk(KERN_ERR PFX "%s: reinit failure (status = %d)."
                               " Rescheduling.\n", dev->name, ret);
                }
                rtl8169_schedule_work(dev, rtl8169_reinit_task);
@@ -2340,9 +2460,10 @@ static void rtl8169_reset_task(struct work_struct *work)
                rtl8169_init_ring_indexes(tp);
                rtl_hw_start(dev);
                netif_wake_queue(dev);
+               rtl8169_check_link_status(dev, tp, tp->mmio_addr);
        } else {
                if (net_ratelimit() && netif_msg_intr(tp)) {
-                       printk(PFX KERN_EMERG "%s: Rx buffers shortage\n",
+                       printk(KERN_EMERG PFX "%s: Rx buffers shortage\n",
                               dev->name);
                }
                rtl8169_schedule_work(dev, rtl8169_reset_task);
@@ -2496,7 +2617,7 @@ err_stop:
        netif_stop_queue(dev);
        ret = NETDEV_TX_BUSY;
 err_update_stats:
-       tp->stats.tx_dropped++;
+       dev->stats.tx_dropped++;
        goto out;
 }
 
@@ -2571,8 +2692,8 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
                if (status & DescOwn)
                        break;
 
-               tp->stats.tx_bytes += len;
-               tp->stats.tx_packets++;
+               dev->stats.tx_bytes += len;
+               dev->stats.tx_packets++;
 
                rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry);
 
@@ -2672,14 +2793,14 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
                                       "%s: Rx ERROR. status = %08x\n",
                                       dev->name, status);
                        }
-                       tp->stats.rx_errors++;
+                       dev->stats.rx_errors++;
                        if (status & (RxRWT | RxRUNT))
-                               tp->stats.rx_length_errors++;
+                               dev->stats.rx_length_errors++;
                        if (status & RxCRC)
-                               tp->stats.rx_crc_errors++;
+                               dev->stats.rx_crc_errors++;
                        if (status & RxFOVF) {
                                rtl8169_schedule_work(dev, rtl8169_reset_task);
-                               tp->stats.rx_fifo_errors++;
+                               dev->stats.rx_fifo_errors++;
                        }
                        rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
                } else {
@@ -2694,8 +2815,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
                         * sized frames.
                         */
                        if (unlikely(rtl8169_fragmented_frame(status))) {
-                               tp->stats.rx_dropped++;
-                               tp->stats.rx_length_errors++;
+                               dev->stats.rx_dropped++;
+                               dev->stats.rx_length_errors++;
                                rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
                                continue;
                        }
@@ -2719,8 +2840,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
                                rtl8169_rx_skb(skb);
 
                        dev->last_rx = jiffies;
-                       tp->stats.rx_bytes += pkt_size;
-                       tp->stats.rx_packets++;
+                       dev->stats.rx_bytes += pkt_size;
+                       dev->stats.rx_packets++;
                }
 
                /* Work around for AMD plateform. */
@@ -2881,7 +3002,7 @@ core_down:
        rtl8169_asic_down(ioaddr);
 
        /* Update the error counts. */
-       tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+       dev->stats.rx_missed_errors += RTL_R32(RxMissed);
        RTL_W32(RxMissed, 0);
 
        spin_unlock_irq(&tp->lock);
@@ -2984,7 +3105,9 @@ static void rtl_set_rx_mode(struct net_device *dev)
            (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
+           (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_16) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_17)) {
                mc_filter[0] = 0xffffffff;
                mc_filter[1] = 0xffffffff;
        }
@@ -3011,12 +3134,12 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
 
        if (netif_running(dev)) {
                spin_lock_irqsave(&tp->lock, flags);
-               tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+               dev->stats.rx_missed_errors += RTL_R32(RxMissed);
                RTL_W32(RxMissed, 0);
                spin_unlock_irqrestore(&tp->lock, flags);
        }
 
-       return &tp->stats;
+       return &dev->stats;
 }
 
 #ifdef CONFIG_PM
@@ -3037,14 +3160,15 @@ static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state)
 
        rtl8169_asic_down(ioaddr);
 
-       tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+       dev->stats.rx_missed_errors += RTL_R32(RxMissed);
        RTL_W32(RxMissed, 0);
 
        spin_unlock_irq(&tp->lock);
 
 out_pci_suspend:
        pci_save_state(pdev);
-       pci_enable_wake(pdev, pci_choose_state(pdev, state), tp->wol_enabled);
+       pci_enable_wake(pdev, pci_choose_state(pdev, state),
+               (tp->features & RTL_FEATURE_WOL) ? 1 : 0);
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
        return 0;
index 014dc2c..09440d7 100644 (file)
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.84"
-#define DRV_MODULE_RELDATE     "October 12, 2007"
+#define DRV_MODULE_VERSION     "3.85"
+#define DRV_MODULE_RELDATE     "October 18, 2007"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -200,6 +200,7 @@ static struct pci_device_id tg3_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
@@ -5028,10 +5029,7 @@ static int tg3_poll_fw(struct tg3 *tp)
 /* Save PCI command register before chip reset */
 static void tg3_save_pci_state(struct tg3 *tp)
 {
-       u32 val;
-
-       pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
-       tp->pci_cmd = val;
+       pci_read_config_word(tp->pdev, PCI_COMMAND, &tp->pci_cmd);
 }
 
 /* Restore PCI state after chip reset */
@@ -5054,7 +5052,7 @@ static void tg3_restore_pci_state(struct tg3 *tp)
                       PCISTATE_ALLOW_APE_SHMEM_WR;
        pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
 
-       pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+       pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
 
        if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
                pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
@@ -10820,9 +10818,24 @@ out_not_found:
                strcpy(tp->board_part_number, "none");
 }
 
+static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
+{
+       u32 val;
+
+       if (tg3_nvram_read_swab(tp, offset, &val) ||
+           (val & 0xfc000000) != 0x0c000000 ||
+           tg3_nvram_read_swab(tp, offset + 4, &val) ||
+           val != 0)
+               return 0;
+
+       return 1;
+}
+
 static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 {
        u32 val, offset, start;
+       u32 ver_offset;
+       int i, bcnt;
 
        if (tg3_nvram_read_swab(tp, 0, &val))
                return;
@@ -10835,29 +10848,71 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
                return;
 
        offset = tg3_nvram_logical_addr(tp, offset);
-       if (tg3_nvram_read_swab(tp, offset, &val))
+
+       if (!tg3_fw_img_is_valid(tp, offset) ||
+           tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
                return;
 
-       if ((val & 0xfc000000) == 0x0c000000) {
-               u32 ver_offset, addr;
-               int i;
+       offset = offset + ver_offset - start;
+       for (i = 0; i < 16; i += 4) {
+               if (tg3_nvram_read(tp, offset + i, &val))
+                       return;
 
-               if (tg3_nvram_read_swab(tp, offset + 4, &val) ||
-                   tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
+               val = le32_to_cpu(val);
+               memcpy(tp->fw_ver + i, &val, 4);
+       }
+
+       if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+            (tp->tg3_flags & TG3_FLG3_ENABLE_APE))
+               return;
+
+       for (offset = TG3_NVM_DIR_START;
+            offset < TG3_NVM_DIR_END;
+            offset += TG3_NVM_DIRENT_SIZE) {
+               if (tg3_nvram_read_swab(tp, offset, &val))
                        return;
 
-               if (val != 0)
+               if ((val >> TG3_NVM_DIRTYPE_SHIFT) == TG3_NVM_DIRTYPE_ASFINI)
+                       break;
+       }
+
+       if (offset == TG3_NVM_DIR_END)
+               return;
+
+       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+               start = 0x08000000;
+       else if (tg3_nvram_read_swab(tp, offset - 4, &start))
+               return;
+
+       if (tg3_nvram_read_swab(tp, offset + 4, &offset) ||
+           !tg3_fw_img_is_valid(tp, offset) ||
+           tg3_nvram_read_swab(tp, offset + 8, &val))
+               return;
+
+       offset += val - start;
+
+       bcnt = strlen(tp->fw_ver);
+
+       tp->fw_ver[bcnt++] = ',';
+       tp->fw_ver[bcnt++] = ' ';
+
+       for (i = 0; i < 4; i++) {
+               if (tg3_nvram_read(tp, offset, &val))
                        return;
 
-               addr = offset + ver_offset - start;
-               for (i = 0; i < 16; i += 4) {
-                       if (tg3_nvram_read(tp, addr + i, &val))
-                               return;
+               val = le32_to_cpu(val);
+               offset += sizeof(val);
 
-                       val = cpu_to_le32(val);
-                       memcpy(tp->fw_ver + i, &val, 4);
+               if (bcnt > TG3_VER_SIZE - sizeof(val)) {
+                       memcpy(&tp->fw_ver[bcnt], &val, TG3_VER_SIZE - bcnt);
+                       break;
                }
+
+               memcpy(&tp->fw_ver[bcnt], &val, sizeof(val));
+               bcnt += sizeof(val);
        }
+
+       tp->fw_ver[TG3_VER_SIZE - 1] = 0;
 }
 
 static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
index 6dbdad2..1d5b2a3 100644 (file)
 #define TG3_EEPROM_MAGIC_HW            0xabcd
 #define TG3_EEPROM_MAGIC_HW_MSK                0xffff
 
+#define TG3_NVM_DIR_START              0x18
+#define TG3_NVM_DIR_END                        0x78
+#define TG3_NVM_DIRENT_SIZE            0xc
+#define TG3_NVM_DIRTYPE_SHIFT          24
+#define TG3_NVM_DIRTYPE_ASFINI         1
+
 /* 32K Window into NIC internal memory */
 #define NIC_SRAM_WIN_BASE              0x00008000
 
@@ -2415,10 +2421,11 @@ struct tg3 {
 #define PHY_REV_BCM5411_X0             0x1 /* Found on Netgear GA302T */
 
        u32                             led_ctrl;
-       u32                             pci_cmd;
+       u16                             pci_cmd;
 
        char                            board_part_number[24];
-       char                            fw_ver[16];
+#define TG3_VER_SIZE 32
+       char                            fw_ver[TG3_VER_SIZE];
        u32                             nic_sram_data_cfg;
        u32                             pci_clock_ctrl;
        struct pci_dev                  *pdev_peer;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
new file mode 100644 (file)
index 0000000..e396c9d
--- /dev/null
@@ -0,0 +1,435 @@
+/* A simple network driver using virtio.
+ *
+ * Copyright 2007 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+//#define DEBUG
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/virtio_net.h>
+#include <linux/scatterlist.h>
+
+/* FIXME: MTU in config. */
+#define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN)
+
+struct virtnet_info
+{
+       struct virtio_device *vdev;
+       struct virtqueue *rvq, *svq;
+       struct net_device *dev;
+       struct napi_struct napi;
+
+       /* Number of input buffers, and max we've ever had. */
+       unsigned int num, max;
+
+       /* Receive & send queues. */
+       struct sk_buff_head recv;
+       struct sk_buff_head send;
+};
+
+static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb)
+{
+       return (struct virtio_net_hdr *)skb->cb;
+}
+
+static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb)
+{
+       sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr));
+}
+
+static bool skb_xmit_done(struct virtqueue *rvq)
+{
+       struct virtnet_info *vi = rvq->vdev->priv;
+
+       /* In case we were waiting for output buffers. */
+       netif_wake_queue(vi->dev);
+       return true;
+}
+
+static void receive_skb(struct net_device *dev, struct sk_buff *skb,
+                       unsigned len)
+{
+       struct virtio_net_hdr *hdr = skb_vnet_hdr(skb);
+
+       if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
+               pr_debug("%s: short packet %i\n", dev->name, len);
+               dev->stats.rx_length_errors++;
+               goto drop;
+       }
+       len -= sizeof(struct virtio_net_hdr);
+       BUG_ON(len > MAX_PACKET_LEN);
+
+       skb_trim(skb, len);
+       skb->protocol = eth_type_trans(skb, dev);
+       pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
+                ntohs(skb->protocol), skb->len, skb->pkt_type);
+       dev->stats.rx_bytes += skb->len;
+       dev->stats.rx_packets++;
+
+       if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+               pr_debug("Needs csum!\n");
+               skb->ip_summed = CHECKSUM_PARTIAL;
+               skb->csum_start = hdr->csum_start;
+               skb->csum_offset = hdr->csum_offset;
+               if (skb->csum_start > skb->len - 2
+                   || skb->csum_offset > skb->len - 2) {
+                       if (net_ratelimit())
+                               printk(KERN_WARNING "%s: csum=%u/%u len=%u\n",
+                                      dev->name, skb->csum_start,
+                                      skb->csum_offset, skb->len);
+                       goto frame_err;
+               }
+       }
+
+       if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+               pr_debug("GSO!\n");
+               switch (hdr->gso_type) {
+               case VIRTIO_NET_HDR_GSO_TCPV4:
+                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+                       break;
+               case VIRTIO_NET_HDR_GSO_TCPV4_ECN:
+                       skb_shinfo(skb)->gso_type = SKB_GSO_TCP_ECN;
+                       break;
+               case VIRTIO_NET_HDR_GSO_UDP:
+                       skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+                       break;
+               case VIRTIO_NET_HDR_GSO_TCPV6:
+                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+                       break;
+               default:
+                       if (net_ratelimit())
+                               printk(KERN_WARNING "%s: bad gso type %u.\n",
+                                      dev->name, hdr->gso_type);
+                       goto frame_err;
+               }
+
+               skb_shinfo(skb)->gso_size = hdr->gso_size;
+               if (skb_shinfo(skb)->gso_size == 0) {
+                       if (net_ratelimit())
+                               printk(KERN_WARNING "%s: zero gso size.\n",
+                                      dev->name);
+                       goto frame_err;
+               }
+
+               /* Header must be checked, and gso_segs computed. */
+               skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+               skb_shinfo(skb)->gso_segs = 0;
+       }
+
+       netif_receive_skb(skb);
+       return;
+
+frame_err:
+       dev->stats.rx_frame_errors++;
+drop:
+       dev_kfree_skb(skb);
+}
+
+static void try_fill_recv(struct virtnet_info *vi)
+{
+       struct sk_buff *skb;
+       struct scatterlist sg[1+MAX_SKB_FRAGS];
+       int num, err;
+
+       for (;;) {
+               skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN);
+               if (unlikely(!skb))
+                       break;
+
+               skb_put(skb, MAX_PACKET_LEN);
+               vnet_hdr_to_sg(sg, skb);
+               num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
+               skb_queue_head(&vi->recv, skb);
+
+               err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb);
+               if (err) {
+                       skb_unlink(skb, &vi->recv);
+                       kfree_skb(skb);
+                       break;
+               }
+               vi->num++;
+       }
+       if (unlikely(vi->num > vi->max))
+               vi->max = vi->num;
+       vi->rvq->vq_ops->kick(vi->rvq);
+}
+
+static bool skb_recv_done(struct virtqueue *rvq)
+{
+       struct virtnet_info *vi = rvq->vdev->priv;
+       netif_rx_schedule(vi->dev, &vi->napi);
+       /* Suppress further interrupts. */
+       return false;
+}
+
+static int virtnet_poll(struct napi_struct *napi, int budget)
+{
+       struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
+       struct sk_buff *skb = NULL;
+       unsigned int len, received = 0;
+
+again:
+       while (received < budget &&
+              (skb = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
+               __skb_unlink(skb, &vi->recv);
+               receive_skb(vi->dev, skb, len);
+               vi->num--;
+               received++;
+       }
+
+       /* FIXME: If we oom and completely run out of inbufs, we need
+        * to start a timer trying to fill more. */
+       if (vi->num < vi->max / 2)
+               try_fill_recv(vi);
+
+       /* All done? */
+       if (!skb) {
+               netif_rx_complete(vi->dev, napi);
+               if (unlikely(!vi->rvq->vq_ops->restart(vi->rvq))
+                   && netif_rx_reschedule(vi->dev, napi))
+                       goto again;
+       }
+
+       return received;
+}
+
+static void free_old_xmit_skbs(struct virtnet_info *vi)
+{
+       struct sk_buff *skb;
+       unsigned int len;
+
+       while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
+               pr_debug("Sent skb %p\n", skb);
+               __skb_unlink(skb, &vi->send);
+               vi->dev->stats.tx_bytes += len;
+               vi->dev->stats.tx_packets++;
+               kfree_skb(skb);
+       }
+}
+
+static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
+       int num, err;
+       struct scatterlist sg[1+MAX_SKB_FRAGS];
+       struct virtio_net_hdr *hdr;
+       const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
+       DECLARE_MAC_BUF(mac);
+
+       pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest));
+
+       free_old_xmit_skbs(vi);
+
+       /* Encode metadata header at front. */
+       hdr = skb_vnet_hdr(skb);
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+               hdr->csum_start = skb->csum_start - skb_headroom(skb);
+               hdr->csum_offset = skb->csum_offset;
+       } else {
+               hdr->flags = 0;
+               hdr->csum_offset = hdr->csum_start = 0;
+       }
+
+       if (skb_is_gso(skb)) {
+               hdr->gso_size = skb_shinfo(skb)->gso_size;
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
+                       hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4_ECN;
+               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+                       hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+                       hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+               else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
+                       hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
+               else
+                       BUG();
+       } else {
+               hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+               hdr->gso_size = 0;
+       }
+
+       vnet_hdr_to_sg(sg, skb);
+       num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
+       __skb_queue_head(&vi->send, skb);
+       err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+       if (err) {
+               pr_debug("%s: virtio not prepared to send\n", dev->name);
+               skb_unlink(skb, &vi->send);
+               netif_stop_queue(dev);
+               return NETDEV_TX_BUSY;
+       }
+       vi->svq->vq_ops->kick(vi->svq);
+
+       return 0;
+}
+
+static int virtnet_open(struct net_device *dev)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
+
+       try_fill_recv(vi);
+
+       /* If we didn't even get one input buffer, we're useless. */
+       if (vi->num == 0)
+               return -ENOMEM;
+
+       napi_enable(&vi->napi);
+       return 0;
+}
+
+static int virtnet_close(struct net_device *dev)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
+       struct sk_buff *skb;
+
+       napi_disable(&vi->napi);
+
+       /* networking core has neutered skb_xmit_done/skb_recv_done, so don't
+        * worry about races vs. get(). */
+       vi->rvq->vq_ops->shutdown(vi->rvq);
+       while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
+               kfree_skb(skb);
+               vi->num--;
+       }
+       vi->svq->vq_ops->shutdown(vi->svq);
+       while ((skb = __skb_dequeue(&vi->send)) != NULL)
+               kfree_skb(skb);
+
+       BUG_ON(vi->num != 0);
+       return 0;
+}
+
+static int virtnet_probe(struct virtio_device *vdev)
+{
+       int err;
+       unsigned int len;
+       struct net_device *dev;
+       struct virtnet_info *vi;
+       void *token;
+
+       /* Allocate ourselves a network device with room for our info */
+       dev = alloc_etherdev(sizeof(struct virtnet_info));
+       if (!dev)
+               return -ENOMEM;
+
+       /* Set up network device as normal. */
+       ether_setup(dev);
+       dev->open = virtnet_open;
+       dev->stop = virtnet_close;
+       dev->hard_start_xmit = start_xmit;
+       dev->features = NETIF_F_HIGHDMA;
+       SET_NETDEV_DEV(dev, &vdev->dev);
+
+       /* Do we support "hardware" checksums? */
+       token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_F, &len);
+       if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_NO_CSUM)) {
+               /* This opens up the world of extra features. */
+               dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+               if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4))
+                       dev->features |= NETIF_F_TSO;
+               if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_UFO))
+                       dev->features |= NETIF_F_UFO;
+               if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4_ECN))
+                       dev->features |= NETIF_F_TSO_ECN;
+               if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO6))
+                       dev->features |= NETIF_F_TSO6;
+       }
+
+       /* Configuration may specify what MAC to use.  Otherwise random. */
+       token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_MAC_F, &len);
+       if (token) {
+               dev->addr_len = len;
+               vdev->config->get(vdev, token, dev->dev_addr, len);
+       } else
+               random_ether_addr(dev->dev_addr);
+
+       /* Set up our device-specific information */
+       vi = netdev_priv(dev);
+       netif_napi_add(dev, &vi->napi, virtnet_poll, 16);
+       vi->dev = dev;
+       vi->vdev = vdev;
+
+       /* We expect two virtqueues, receive then send. */
+       vi->rvq = vdev->config->find_vq(vdev, skb_recv_done);
+       if (IS_ERR(vi->rvq)) {
+               err = PTR_ERR(vi->rvq);
+               goto free;
+       }
+
+       vi->svq = vdev->config->find_vq(vdev, skb_xmit_done);
+       if (IS_ERR(vi->svq)) {
+               err = PTR_ERR(vi->svq);
+               goto free_recv;
+       }
+
+       /* Initialize our empty receive and send queues. */
+       skb_queue_head_init(&vi->recv);
+       skb_queue_head_init(&vi->send);
+
+       err = register_netdev(dev);
+       if (err) {
+               pr_debug("virtio_net: registering device failed\n");
+               goto free_send;
+       }
+       pr_debug("virtnet: registered device %s\n", dev->name);
+       vdev->priv = vi;
+       return 0;
+
+free_send:
+       vdev->config->del_vq(vi->svq);
+free_recv:
+       vdev->config->del_vq(vi->rvq);
+free:
+       free_netdev(dev);
+       return err;
+}
+
+static void virtnet_remove(struct virtio_device *vdev)
+{
+       unregister_netdev(vdev->priv);
+       free_netdev(vdev->priv);
+}
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static struct virtio_driver virtio_net = {
+       .driver.name =  KBUILD_MODNAME,
+       .driver.owner = THIS_MODULE,
+       .id_table =     id_table,
+       .probe =        virtnet_probe,
+       .remove =       __devexit_p(virtnet_remove),
+};
+
+static int __init init(void)
+{
+       return register_virtio_driver(&virtio_net);
+}
+
+static void __exit fini(void)
+{
+       unregister_virtio_driver(&virtio_net);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio network driver");
+MODULE_LICENSE("GPL");
index b3c4dbf..7c60cbd 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/reboot.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/scatterlist.h>
 
 #include <asm/byteorder.h>
 #include <asm/cache.h>         /* for L1_CACHE_BYTES */
index 5b86ee5..5eace9e 100644 (file)
@@ -556,44 +556,6 @@ lba_bios_init(void)
 
 #ifdef CONFIG_64BIT
 
-/*
-** Determine if a device is already configured.
-** If so, reserve it resources.
-**
-** Read PCI cfg command register and see if I/O or MMIO is enabled.
-** PAT has to enable the devices it's using.
-**
-** Note: resources are fixed up before we try to claim them.
-*/
-static void
-lba_claim_dev_resources(struct pci_dev *dev)
-{
-       u16 cmd;
-       int i, srch_flags;
-
-       (void) pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-       srch_flags  = (cmd & PCI_COMMAND_IO) ? IORESOURCE_IO : 0;
-       if (cmd & PCI_COMMAND_MEMORY)
-               srch_flags |= IORESOURCE_MEM;
-
-       if (!srch_flags)
-               return;
-
-       for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
-               if (dev->resource[i].flags & srch_flags) {
-                       pci_claim_resource(dev, i);
-                       DBG("   claimed %s %d [%lx,%lx]/%lx\n",
-                               pci_name(dev), i,
-                               dev->resource[i].start,
-                               dev->resource[i].end,
-                               dev->resource[i].flags
-                               );
-               }
-       }
-}
-
-
 /*
  * truncate_pat_collision:  Deal with overlaps or outright collisions
  *                     between PAT PDC reported ranges.
@@ -653,7 +615,6 @@ truncate_pat_collision(struct resource *root, struct resource *new)
 }
 
 #else
-#define lba_claim_dev_resources(dev) do { } while (0)
 #define truncate_pat_collision(r,n)  (0)
 #endif
 
@@ -684,8 +645,12 @@ lba_fixup_bus(struct pci_bus *bus)
        ** pci_alloc_primary_bus() mangles this.
        */
        if (bus->self) {
+               int i;
                /* PCI-PCI Bridge */
                pci_read_bridge_bases(bus);
+               for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+                       pci_claim_resource(bus->self, i);
+               }
        } else {
                /* Host-PCI Bridge */
                int err, i;
@@ -803,6 +768,9 @@ lba_fixup_bus(struct pci_bus *bus)
                                DBG("lba_fixup_bus() WTF? 0x%lx [%lx/%lx] XXX",
                                        res->flags, res->start, res->end);
                        }
+                       if ((i != PCI_ROM_RESOURCE) ||
+                           (res->flags & IORESOURCE_ROM_ENABLE))
+                               pci_claim_resource(dev, i);
                }
 
 #ifdef FBB_SUPPORT
@@ -814,11 +782,6 @@ lba_fixup_bus(struct pci_bus *bus)
                bus->bridge_ctl &= ~(status & PCI_STATUS_FAST_BACK);
 #endif
 
-               if (is_pdc_pat()) {
-                       /* Claim resources for PDC's devices */
-                       lba_claim_dev_resources(dev);
-               }
-
                 /*
                ** P2PB's have no IRQs. ignore them.
                */
index fc4bde2..ebb09e9 100644 (file)
@@ -282,6 +282,7 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
        unsigned short i;
        char in[count+1], *temp;
        struct device *dev;
+       int ret;
 
        if (!entry || !buf || !count)
                return -EINVAL;
@@ -333,7 +334,9 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
        
        /* Update the symlink to the real device */
        sysfs_remove_link(&entry->kobj, "device");
-       sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+       ret = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+       WARN_ON(ret);
+
        write_unlock(&entry->rw_lock);
        
        printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n",
@@ -1003,8 +1006,10 @@ pdcs_register_pathentries(void)
                entry->ready = 2;
                
                /* Add a nice symlink to the real device */
-               if (entry->dev)
-                       sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+               if (entry->dev) {
+                       err = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+                       WARN_ON(err);
+               }
 
                write_unlock(&entry->rw_lock);
        }
index d044c48..e527a0e 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/scatterlist.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -1909,8 +1910,8 @@ sba_driver_callback(struct parisc_device *dev)
                        global_ioc_cnt *= 2;
        }
 
-       printk(KERN_INFO "%s found %s at 0x%lx\n",
-               MODULE_NAME, version, dev->hpa.start);
+       printk(KERN_INFO "%s found %s at 0x%llx\n",
+               MODULE_NAME, version, (unsigned long long)dev->hpa.start);
 
        sba_dev = kzalloc(sizeof(struct sba_device), GFP_KERNEL);
        if (!sba_dev) {
index 38cdf9f..1e8d2d1 100644 (file)
@@ -155,6 +155,7 @@ superio_init(struct pci_dev *pcidev)
        struct superio_device *sio = &sio_dev;
        struct pci_dev *pdev = sio->lio_pdev;
        u16 word;
+       int ret;
 
        if (sio->suckyio_irq_enabled)
                return;
@@ -200,7 +201,8 @@ superio_init(struct pci_dev *pcidev)
        pci_write_config_word (pdev, PCI_COMMAND, word);
 
        pci_set_master (pdev);
-       pci_enable_device(pdev);
+       ret = pci_enable_device(pdev);
+       BUG_ON(ret < 0);        /* not too much we can do about this... */
 
        /*
         * Next project is programming the onboard interrupt controllers.
index 006054a..5550556 100644 (file)
@@ -20,6 +20,9 @@ obj-$(CONFIG_PCI_MSI) += msi.o
 # Build the Hypertransport interrupt support
 obj-$(CONFIG_HT_IRQ) += htirq.o
 
+# Build Intel IOMMU support
+obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
+
 #
 # Some architectures use the generic PCI setup functions
 #
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
new file mode 100644 (file)
index 0000000..5dfdfda
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ *     Copyright (C) Ashok Raj <ashok.raj@intel.com>
+ *     Copyright (C) Shaohua Li <shaohua.li@intel.com>
+ *     Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ *
+ *     This file implements early detection/parsing of DMA Remapping Devices
+ * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI
+ * tables.
+ */
+
+#include <linux/pci.h>
+#include <linux/dmar.h>
+
+#undef PREFIX
+#define PREFIX "DMAR:"
+
+/* No locks are needed as DMA remapping hardware unit
+ * list is constructed at boot time and hotplug of
+ * these units are not supported by the architecture.
+ */
+LIST_HEAD(dmar_drhd_units);
+LIST_HEAD(dmar_rmrr_units);
+
+static struct acpi_table_header * __initdata dmar_tbl;
+
+static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
+{
+       /*
+        * add INCLUDE_ALL at the tail, so scan the list will find it at
+        * the very end.
+        */
+       if (drhd->include_all)
+               list_add_tail(&drhd->list, &dmar_drhd_units);
+       else
+               list_add(&drhd->list, &dmar_drhd_units);
+}
+
+static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
+{
+       list_add(&rmrr->list, &dmar_rmrr_units);
+}
+
+static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
+                                          struct pci_dev **dev, u16 segment)
+{
+       struct pci_bus *bus;
+       struct pci_dev *pdev = NULL;
+       struct acpi_dmar_pci_path *path;
+       int count;
+
+       bus = pci_find_bus(segment, scope->bus);
+       path = (struct acpi_dmar_pci_path *)(scope + 1);
+       count = (scope->length - sizeof(struct acpi_dmar_device_scope))
+               / sizeof(struct acpi_dmar_pci_path);
+
+       while (count) {
+               if (pdev)
+                       pci_dev_put(pdev);
+               /*
+                * Some BIOSes list non-exist devices in DMAR table, just
+                * ignore it
+                */
+               if (!bus) {
+                       printk(KERN_WARNING
+                       PREFIX "Device scope bus [%d] not found\n",
+                       scope->bus);
+                       break;
+               }
+               pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn));
+               if (!pdev) {
+                       printk(KERN_WARNING PREFIX
+                       "Device scope device [%04x:%02x:%02x.%02x] not found\n",
+                               segment, bus->number, path->dev, path->fn);
+                       break;
+               }
+               path ++;
+               count --;
+               bus = pdev->subordinate;
+       }
+       if (!pdev) {
+               printk(KERN_WARNING PREFIX
+               "Device scope device [%04x:%02x:%02x.%02x] not found\n",
+               segment, scope->bus, path->dev, path->fn);
+               *dev = NULL;
+               return 0;
+       }
+       if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \
+                       pdev->subordinate) || (scope->entry_type == \
+                       ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) {
+               pci_dev_put(pdev);
+               printk(KERN_WARNING PREFIX
+                       "Device scope type does not match for %s\n",
+                        pci_name(pdev));
+               return -EINVAL;
+       }
+       *dev = pdev;
+       return 0;
+}
+
+static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
+                                      struct pci_dev ***devices, u16 segment)
+{
+       struct acpi_dmar_device_scope *scope;
+       void * tmp = start;
+       int index;
+       int ret;
+
+       *cnt = 0;
+       while (start < end) {
+               scope = start;
+               if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
+                   scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
+                       (*cnt)++;
+               else
+                       printk(KERN_WARNING PREFIX
+                               "Unsupported device scope\n");
+               start += scope->length;
+       }
+       if (*cnt == 0)
+               return 0;
+
+       *devices = kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL);
+       if (!*devices)
+               return -ENOMEM;
+
+       start = tmp;
+       index = 0;
+       while (start < end) {
+               scope = start;
+               if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
+                   scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) {
+                       ret = dmar_parse_one_dev_scope(scope,
+                               &(*devices)[index], segment);
+                       if (ret) {
+                               kfree(*devices);
+                               return ret;
+                       }
+                       index ++;
+               }
+               start += scope->length;
+       }
+
+       return 0;
+}
+
+/**
+ * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition
+ * structure which uniquely represent one DMA remapping hardware unit
+ * present in the platform
+ */
+static int __init
+dmar_parse_one_drhd(struct acpi_dmar_header *header)
+{
+       struct acpi_dmar_hardware_unit *drhd;
+       struct dmar_drhd_unit *dmaru;
+       int ret = 0;
+       static int include_all;
+
+       dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
+       if (!dmaru)
+               return -ENOMEM;
+
+       drhd = (struct acpi_dmar_hardware_unit *)header;
+       dmaru->reg_base_addr = drhd->address;
+       dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
+
+       if (!dmaru->include_all)
+               ret = dmar_parse_dev_scope((void *)(drhd + 1),
+                               ((void *)drhd) + header->length,
+                               &dmaru->devices_cnt, &dmaru->devices,
+                               drhd->segment);
+       else {
+               /* Only allow one INCLUDE_ALL */
+               if (include_all) {
+                       printk(KERN_WARNING PREFIX "Only one INCLUDE_ALL "
+                               "device scope is allowed\n");
+                       ret = -EINVAL;
+               }
+               include_all = 1;
+       }
+
+       if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all))
+               kfree(dmaru);
+       else
+               dmar_register_drhd_unit(dmaru);
+       return ret;
+}
+
+static int __init
+dmar_parse_one_rmrr(struct acpi_dmar_header *header)
+{
+       struct acpi_dmar_reserved_memory *rmrr;
+       struct dmar_rmrr_unit *rmrru;
+       int ret = 0;
+
+       rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
+       if (!rmrru)
+               return -ENOMEM;
+
+       rmrr = (struct acpi_dmar_reserved_memory *)header;
+       rmrru->base_address = rmrr->base_address;
+       rmrru->end_address = rmrr->end_address;
+       ret = dmar_parse_dev_scope((void *)(rmrr + 1),
+               ((void *)rmrr) + header->length,
+               &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
+
+       if (ret || (rmrru->devices_cnt == 0))
+               kfree(rmrru);
+       else
+               dmar_register_rmrr_unit(rmrru);
+       return ret;
+}
+
+static void __init
+dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
+{
+       struct acpi_dmar_hardware_unit *drhd;
+       struct acpi_dmar_reserved_memory *rmrr;
+
+       switch (header->type) {
+       case ACPI_DMAR_TYPE_HARDWARE_UNIT:
+               drhd = (struct acpi_dmar_hardware_unit *)header;
+               printk (KERN_INFO PREFIX
+                       "DRHD (flags: 0x%08x)base: 0x%016Lx\n",
+                       drhd->flags, drhd->address);
+               break;
+       case ACPI_DMAR_TYPE_RESERVED_MEMORY:
+               rmrr = (struct acpi_dmar_reserved_memory *)header;
+
+               printk (KERN_INFO PREFIX
+                       "RMRR base: 0x%016Lx end: 0x%016Lx\n",
+                       rmrr->base_address, rmrr->end_address);
+               break;
+       }
+}
+
+/**
+ * parse_dmar_table - parses the DMA reporting table
+ */
+static int __init
+parse_dmar_table(void)
+{
+       struct acpi_table_dmar *dmar;
+       struct acpi_dmar_header *entry_header;
+       int ret = 0;
+
+       dmar = (struct acpi_table_dmar *)dmar_tbl;
+       if (!dmar)
+               return -ENODEV;
+
+       if (!dmar->width) {
+               printk (KERN_WARNING PREFIX "Zero: Invalid DMAR haw\n");
+               return -EINVAL;
+       }
+
+       printk (KERN_INFO PREFIX "Host address width %d\n",
+               dmar->width + 1);
+
+       entry_header = (struct acpi_dmar_header *)(dmar + 1);
+       while (((unsigned long)entry_header) <
+                       (((unsigned long)dmar) + dmar_tbl->length)) {
+               dmar_table_print_dmar_entry(entry_header);
+
+               switch (entry_header->type) {
+               case ACPI_DMAR_TYPE_HARDWARE_UNIT:
+                       ret = dmar_parse_one_drhd(entry_header);
+                       break;
+               case ACPI_DMAR_TYPE_RESERVED_MEMORY:
+                       ret = dmar_parse_one_rmrr(entry_header);
+                       break;
+               default:
+                       printk(KERN_WARNING PREFIX
+                               "Unknown DMAR structure type\n");
+                       ret = 0; /* for forward compatibility */
+                       break;
+               }
+               if (ret)
+                       break;
+
+               entry_header = ((void *)entry_header + entry_header->length);
+       }
+       return ret;
+}
+
+
+int __init dmar_table_init(void)
+{
+
+       parse_dmar_table();
+       if (list_empty(&dmar_drhd_units)) {
+               printk(KERN_INFO PREFIX "No DMAR devices found\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+/**
+ * early_dmar_detect - checks to see if the platform supports DMAR devices
+ */
+int __init early_dmar_detect(void)
+{
+       acpi_status status = AE_OK;
+
+       /* if we could find DMAR table, then there are DMAR devices */
+       status = acpi_get_table(ACPI_SIG_DMAR, 0,
+                               (struct acpi_table_header **)&dmar_tbl);
+
+       if (ACPI_SUCCESS(status) && !dmar_tbl) {
+               printk (KERN_WARNING PREFIX "Unable to map DMAR\n");
+               status = AE_NOT_FOUND;
+       }
+
+       return (ACPI_SUCCESS(status) ? 1 : 0);
+}
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
new file mode 100644 (file)
index 0000000..0c4ab3b
--- /dev/null
@@ -0,0 +1,2271 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Ashok Raj <ashok.raj@intel.com>
+ * Copyright (C) Shaohua Li <shaohua.li@intel.com>
+ * Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ */
+
+#include <linux/init.h>
+#include <linux/bitmap.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/sysdev.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/dmar.h>
+#include <linux/dma-mapping.h>
+#include <linux/mempool.h>
+#include "iova.h"
+#include "intel-iommu.h"
+#include <asm/proto.h> /* force_iommu in this header in x86-64*/
+#include <asm/cacheflush.h>
+#include <asm/iommu.h>
+#include "pci.h"
+
+#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
+#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
+
+#define IOAPIC_RANGE_START     (0xfee00000)
+#define IOAPIC_RANGE_END       (0xfeefffff)
+#define IOVA_START_ADDR                (0x1000)
+
+#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
+
+#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
+
+#define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
+
+static void domain_remove_dev_info(struct dmar_domain *domain);
+
+static int dmar_disabled;
+static int __initdata dmar_map_gfx = 1;
+static int dmar_forcedac;
+
+#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
+static DEFINE_SPINLOCK(device_domain_lock);
+static LIST_HEAD(device_domain_list);
+
+static int __init intel_iommu_setup(char *str)
+{
+       if (!str)
+               return -EINVAL;
+       while (*str) {
+               if (!strncmp(str, "off", 3)) {
+                       dmar_disabled = 1;
+                       printk(KERN_INFO"Intel-IOMMU: disabled\n");
+               } else if (!strncmp(str, "igfx_off", 8)) {
+                       dmar_map_gfx = 0;
+                       printk(KERN_INFO
+                               "Intel-IOMMU: disable GFX device mapping\n");
+               } else if (!strncmp(str, "forcedac", 8)) {
+                       printk (KERN_INFO
+                               "Intel-IOMMU: Forcing DAC for PCI devices\n");
+                       dmar_forcedac = 1;
+               }
+
+               str += strcspn(str, ",");
+               while (*str == ',')
+                       str++;
+       }
+       return 0;
+}
+__setup("intel_iommu=", intel_iommu_setup);
+
+static struct kmem_cache *iommu_domain_cache;
+static struct kmem_cache *iommu_devinfo_cache;
+static struct kmem_cache *iommu_iova_cache;
+
+static inline void *iommu_kmem_cache_alloc(struct kmem_cache *cachep)
+{
+       unsigned int flags;
+       void *vaddr;
+
+       /* trying to avoid low memory issues */
+       flags = current->flags & PF_MEMALLOC;
+       current->flags |= PF_MEMALLOC;
+       vaddr = kmem_cache_alloc(cachep, GFP_ATOMIC);
+       current->flags &= (~PF_MEMALLOC | flags);
+       return vaddr;
+}
+
+
+static inline void *alloc_pgtable_page(void)
+{
+       unsigned int flags;
+       void *vaddr;
+
+       /* trying to avoid low memory issues */
+       flags = current->flags & PF_MEMALLOC;
+       current->flags |= PF_MEMALLOC;
+       vaddr = (void *)get_zeroed_page(GFP_ATOMIC);
+       current->flags &= (~PF_MEMALLOC | flags);
+       return vaddr;
+}
+
+static inline void free_pgtable_page(void *vaddr)
+{
+       free_page((unsigned long)vaddr);
+}
+
+static inline void *alloc_domain_mem(void)
+{
+       return iommu_kmem_cache_alloc(iommu_domain_cache);
+}
+
+static inline void free_domain_mem(void *vaddr)
+{
+       kmem_cache_free(iommu_domain_cache, vaddr);
+}
+
+static inline void * alloc_devinfo_mem(void)
+{
+       return iommu_kmem_cache_alloc(iommu_devinfo_cache);
+}
+
+static inline void free_devinfo_mem(void *vaddr)
+{
+       kmem_cache_free(iommu_devinfo_cache, vaddr);
+}
+
+struct iova *alloc_iova_mem(void)
+{
+       return iommu_kmem_cache_alloc(iommu_iova_cache);
+}
+
+void free_iova_mem(struct iova *iova)
+{
+       kmem_cache_free(iommu_iova_cache, iova);
+}
+
+static inline void __iommu_flush_cache(
+       struct intel_iommu *iommu, void *addr, int size)
+{
+       if (!ecap_coherent(iommu->ecap))
+               clflush_cache_range(addr, size);
+}
+
+/* Gets context entry for a given bus and devfn */
+static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
+               u8 bus, u8 devfn)
+{
+       struct root_entry *root;
+       struct context_entry *context;
+       unsigned long phy_addr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       root = &iommu->root_entry[bus];
+       context = get_context_addr_from_root(root);
+       if (!context) {
+               context = (struct context_entry *)alloc_pgtable_page();
+               if (!context) {
+                       spin_unlock_irqrestore(&iommu->lock, flags);
+                       return NULL;
+               }
+               __iommu_flush_cache(iommu, (void *)context, PAGE_SIZE_4K);
+               phy_addr = virt_to_phys((void *)context);
+               set_root_value(root, phy_addr);
+               set_root_present(root);
+               __iommu_flush_cache(iommu, root, sizeof(*root));
+       }
+       spin_unlock_irqrestore(&iommu->lock, flags);
+       return &context[devfn];
+}
+
+static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+       struct root_entry *root;
+       struct context_entry *context;
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       root = &iommu->root_entry[bus];
+       context = get_context_addr_from_root(root);
+       if (!context) {
+               ret = 0;
+               goto out;
+       }
+       ret = context_present(context[devfn]);
+out:
+       spin_unlock_irqrestore(&iommu->lock, flags);
+       return ret;
+}
+
+static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+       struct root_entry *root;
+       struct context_entry *context;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       root = &iommu->root_entry[bus];
+       context = get_context_addr_from_root(root);
+       if (context) {
+               context_clear_entry(context[devfn]);
+               __iommu_flush_cache(iommu, &context[devfn], \
+                       sizeof(*context));
+       }
+       spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static void free_context_table(struct intel_iommu *iommu)
+{
+       struct root_entry *root;
+       int i;
+       unsigned long flags;
+       struct context_entry *context;
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       if (!iommu->root_entry) {
+               goto out;
+       }
+       for (i = 0; i < ROOT_ENTRY_NR; i++) {
+               root = &iommu->root_entry[i];
+               context = get_context_addr_from_root(root);
+               if (context)
+                       free_pgtable_page(context);
+       }
+       free_pgtable_page(iommu->root_entry);
+       iommu->root_entry = NULL;
+out:
+       spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+/* page table handling */
+#define LEVEL_STRIDE           (9)
+#define LEVEL_MASK             (((u64)1 << LEVEL_STRIDE) - 1)
+
+static inline int agaw_to_level(int agaw)
+{
+       return agaw + 2;
+}
+
+static inline int agaw_to_width(int agaw)
+{
+       return 30 + agaw * LEVEL_STRIDE;
+
+}
+
+static inline int width_to_agaw(int width)
+{
+       return (width - 30) / LEVEL_STRIDE;
+}
+
+static inline unsigned int level_to_offset_bits(int level)
+{
+       return (12 + (level - 1) * LEVEL_STRIDE);
+}
+
+static inline int address_level_offset(u64 addr, int level)
+{
+       return ((addr >> level_to_offset_bits(level)) & LEVEL_MASK);
+}
+
+static inline u64 level_mask(int level)
+{
+       return ((u64)-1 << level_to_offset_bits(level));
+}
+
+static inline u64 level_size(int level)
+{
+       return ((u64)1 << level_to_offset_bits(level));
+}
+
+static inline u64 align_to_level(u64 addr, int level)
+{
+       return ((addr + level_size(level) - 1) & level_mask(level));
+}
+
+static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
+{
+       int addr_width = agaw_to_width(domain->agaw);
+       struct dma_pte *parent, *pte = NULL;
+       int level = agaw_to_level(domain->agaw);
+       int offset;
+       unsigned long flags;
+
+       BUG_ON(!domain->pgd);
+
+       addr &= (((u64)1) << addr_width) - 1;
+       parent = domain->pgd;
+
+       spin_lock_irqsave(&domain->mapping_lock, flags);
+       while (level > 0) {
+               void *tmp_page;
+
+               offset = address_level_offset(addr, level);
+               pte = &parent[offset];
+               if (level == 1)
+                       break;
+
+               if (!dma_pte_present(*pte)) {
+                       tmp_page = alloc_pgtable_page();
+
+                       if (!tmp_page) {
+                               spin_unlock_irqrestore(&domain->mapping_lock,
+                                       flags);
+                               return NULL;
+                       }
+                       __iommu_flush_cache(domain->iommu, tmp_page,
+                                       PAGE_SIZE_4K);
+                       dma_set_pte_addr(*pte, virt_to_phys(tmp_page));
+                       /*
+                        * high level table always sets r/w, last level page
+                        * table control read/write
+                        */
+                       dma_set_pte_readable(*pte);
+                       dma_set_pte_writable(*pte);
+                       __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+               }
+               parent = phys_to_virt(dma_pte_addr(*pte));
+               level--;
+       }
+
+       spin_unlock_irqrestore(&domain->mapping_lock, flags);
+       return pte;
+}
+
+/* return address's pte at specific level */
+static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
+               int level)
+{
+       struct dma_pte *parent, *pte = NULL;
+       int total = agaw_to_level(domain->agaw);
+       int offset;
+
+       parent = domain->pgd;
+       while (level <= total) {
+               offset = address_level_offset(addr, total);
+               pte = &parent[offset];
+               if (level == total)
+                       return pte;
+
+               if (!dma_pte_present(*pte))
+                       break;
+               parent = phys_to_virt(dma_pte_addr(*pte));
+               total--;
+       }
+       return NULL;
+}
+
+/* clear one page's page table */
+static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
+{
+       struct dma_pte *pte = NULL;
+
+       /* get last level pte */
+       pte = dma_addr_level_pte(domain, addr, 1);
+
+       if (pte) {
+               dma_clear_pte(*pte);
+               __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+       }
+}
+
+/* clear last level pte, a tlb flush should be followed */
+static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
+{
+       int addr_width = agaw_to_width(domain->agaw);
+
+       start &= (((u64)1) << addr_width) - 1;
+       end &= (((u64)1) << addr_width) - 1;
+       /* in case it's partial page */
+       start = PAGE_ALIGN_4K(start);
+       end &= PAGE_MASK_4K;
+
+       /* we don't need lock here, nobody else touches the iova range */
+       while (start < end) {
+               dma_pte_clear_one(domain, start);
+               start += PAGE_SIZE_4K;
+       }
+}
+
+/* free page table pages. last level pte should already be cleared */
+static void dma_pte_free_pagetable(struct dmar_domain *domain,
+       u64 start, u64 end)
+{
+       int addr_width = agaw_to_width(domain->agaw);
+       struct dma_pte *pte;
+       int total = agaw_to_level(domain->agaw);
+       int level;
+       u64 tmp;
+
+       start &= (((u64)1) << addr_width) - 1;
+       end &= (((u64)1) << addr_width) - 1;
+
+       /* we don't need lock here, nobody else touches the iova range */
+       level = 2;
+       while (level <= total) {
+               tmp = align_to_level(start, level);
+               if (tmp >= end || (tmp + level_size(level) > end))
+                       return;
+
+               while (tmp < end) {
+                       pte = dma_addr_level_pte(domain, tmp, level);
+                       if (pte) {
+                               free_pgtable_page(
+                                       phys_to_virt(dma_pte_addr(*pte)));
+                               dma_clear_pte(*pte);
+                               __iommu_flush_cache(domain->iommu,
+                                               pte, sizeof(*pte));
+                       }
+                       tmp += level_size(level);
+               }
+               level++;
+       }
+       /* free pgd */
+       if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) {
+               free_pgtable_page(domain->pgd);
+               domain->pgd = NULL;
+       }
+}
+
+/* iommu handling */
+static int iommu_alloc_root_entry(struct intel_iommu *iommu)
+{
+       struct root_entry *root;
+       unsigned long flags;
+
+       root = (struct root_entry *)alloc_pgtable_page();
+       if (!root)
+               return -ENOMEM;
+
+       __iommu_flush_cache(iommu, root, PAGE_SIZE_4K);
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       iommu->root_entry = root;
+       spin_unlock_irqrestore(&iommu->lock, flags);
+
+       return 0;
+}
+
+#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
+{\
+       unsigned long start_time = jiffies;\
+       while (1) {\
+               sts = op (iommu->reg + offset);\
+               if (cond)\
+                       break;\
+               if (time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT))\
+                       panic("DMAR hardware is malfunctioning\n");\
+               cpu_relax();\
+       }\
+}
+
+static void iommu_set_root_entry(struct intel_iommu *iommu)
+{
+       void *addr;
+       u32 cmd, sts;
+       unsigned long flag;
+
+       addr = iommu->root_entry;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
+
+       cmd = iommu->gcmd | DMA_GCMD_SRTP;
+       writel(cmd, iommu->reg + DMAR_GCMD_REG);
+
+       /* Make sure hardware complete it */
+       IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+               readl, (sts & DMA_GSTS_RTPS), sts);
+
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+static void iommu_flush_write_buffer(struct intel_iommu *iommu)
+{
+       u32 val;
+       unsigned long flag;
+
+       if (!cap_rwbf(iommu->cap))
+               return;
+       val = iommu->gcmd | DMA_GCMD_WBF;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       writel(val, iommu->reg + DMAR_GCMD_REG);
+
+       /* Make sure hardware complete it */
+       IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+                       readl, (!(val & DMA_GSTS_WBFS)), val);
+
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+/* return value determine if we need a write buffer flush */
+static int __iommu_flush_context(struct intel_iommu *iommu,
+       u16 did, u16 source_id, u8 function_mask, u64 type,
+       int non_present_entry_flush)
+{
+       u64 val = 0;
+       unsigned long flag;
+
+       /*
+        * In the non-present entry flush case, if hardware doesn't cache
+        * non-present entry we do nothing and if hardware cache non-present
+        * entry, we flush entries of domain 0 (the domain id is used to cache
+        * any non-present entries)
+        */
+       if (non_present_entry_flush) {
+               if (!cap_caching_mode(iommu->cap))
+                       return 1;
+               else
+                       did = 0;
+       }
+
+       switch (type) {
+       case DMA_CCMD_GLOBAL_INVL:
+               val = DMA_CCMD_GLOBAL_INVL;
+               break;
+       case DMA_CCMD_DOMAIN_INVL:
+               val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
+               break;
+       case DMA_CCMD_DEVICE_INVL:
+               val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
+                       | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
+               break;
+       default:
+               BUG();
+       }
+       val |= DMA_CCMD_ICC;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
+
+       /* Make sure hardware complete it */
+       IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
+               dmar_readq, (!(val & DMA_CCMD_ICC)), val);
+
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+       /* flush context entry will implictly flush write buffer */
+       return 0;
+}
+
+static int inline iommu_flush_context_global(struct intel_iommu *iommu,
+       int non_present_entry_flush)
+{
+       return __iommu_flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL,
+               non_present_entry_flush);
+}
+
+static int inline iommu_flush_context_domain(struct intel_iommu *iommu, u16 did,
+       int non_present_entry_flush)
+{
+       return __iommu_flush_context(iommu, did, 0, 0, DMA_CCMD_DOMAIN_INVL,
+               non_present_entry_flush);
+}
+
+static int inline iommu_flush_context_device(struct intel_iommu *iommu,
+       u16 did, u16 source_id, u8 function_mask, int non_present_entry_flush)
+{
+       return __iommu_flush_context(iommu, did, source_id, function_mask,
+               DMA_CCMD_DEVICE_INVL, non_present_entry_flush);
+}
+
+/* return value determine if we need a write buffer flush */
+static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
+       u64 addr, unsigned int size_order, u64 type,
+       int non_present_entry_flush)
+{
+       int tlb_offset = ecap_iotlb_offset(iommu->ecap);
+       u64 val = 0, val_iva = 0;
+       unsigned long flag;
+
+       /*
+        * In the non-present entry flush case, if hardware doesn't cache
+        * non-present entry we do nothing and if hardware cache non-present
+        * entry, we flush entries of domain 0 (the domain id is used to cache
+        * any non-present entries)
+        */
+       if (non_present_entry_flush) {
+               if (!cap_caching_mode(iommu->cap))
+                       return 1;
+               else
+                       did = 0;
+       }
+
+       switch (type) {
+       case DMA_TLB_GLOBAL_FLUSH:
+               /* global flush doesn't need set IVA_REG */
+               val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
+               break;
+       case DMA_TLB_DSI_FLUSH:
+               val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
+               break;
+       case DMA_TLB_PSI_FLUSH:
+               val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
+               /* Note: always flush non-leaf currently */
+               val_iva = size_order | addr;
+               break;
+       default:
+               BUG();
+       }
+       /* Note: set drain read/write */
+#if 0
+       /*
+        * This is probably to be super secure.. Looks like we can
+        * ignore it without any impact.
+        */
+       if (cap_read_drain(iommu->cap))
+               val |= DMA_TLB_READ_DRAIN;
+#endif
+       if (cap_write_drain(iommu->cap))
+               val |= DMA_TLB_WRITE_DRAIN;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       /* Note: Only uses first TLB reg currently */
+       if (val_iva)
+               dmar_writeq(iommu->reg + tlb_offset, val_iva);
+       dmar_writeq(iommu->reg + tlb_offset + 8, val);
+
+       /* Make sure hardware complete it */
+       IOMMU_WAIT_OP(iommu, tlb_offset + 8,
+               dmar_readq, (!(val & DMA_TLB_IVT)), val);
+
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+       /* check IOTLB invalidation granularity */
+       if (DMA_TLB_IAIG(val) == 0)
+               printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
+       if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
+               pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
+                       DMA_TLB_IIRG(type), DMA_TLB_IAIG(val));
+       /* flush context entry will implictly flush write buffer */
+       return 0;
+}
+
+static int inline iommu_flush_iotlb_global(struct intel_iommu *iommu,
+       int non_present_entry_flush)
+{
+       return __iommu_flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
+               non_present_entry_flush);
+}
+
+static int inline iommu_flush_iotlb_dsi(struct intel_iommu *iommu, u16 did,
+       int non_present_entry_flush)
+{
+       return __iommu_flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH,
+               non_present_entry_flush);
+}
+
+static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
+       u64 addr, unsigned int pages, int non_present_entry_flush)
+{
+       unsigned int mask;
+
+       BUG_ON(addr & (~PAGE_MASK_4K));
+       BUG_ON(pages == 0);
+
+       /* Fallback to domain selective flush if no PSI support */
+       if (!cap_pgsel_inv(iommu->cap))
+               return iommu_flush_iotlb_dsi(iommu, did,
+                       non_present_entry_flush);
+
+       /*
+        * PSI requires page size to be 2 ^ x, and the base address is naturally
+        * aligned to the size
+        */
+       mask = ilog2(__roundup_pow_of_two(pages));
+       /* Fallback to domain selective flush if size is too big */
+       if (mask > cap_max_amask_val(iommu->cap))
+               return iommu_flush_iotlb_dsi(iommu, did,
+                       non_present_entry_flush);
+
+       return __iommu_flush_iotlb(iommu, did, addr, mask,
+               DMA_TLB_PSI_FLUSH, non_present_entry_flush);
+}
+
+static int iommu_enable_translation(struct intel_iommu *iommu)
+{
+       u32 sts;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu->register_lock, flags);
+       writel(iommu->gcmd|DMA_GCMD_TE, iommu->reg + DMAR_GCMD_REG);
+
+       /* Make sure hardware complete it */
+       IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+               readl, (sts & DMA_GSTS_TES), sts);
+
+       iommu->gcmd |= DMA_GCMD_TE;
+       spin_unlock_irqrestore(&iommu->register_lock, flags);
+       return 0;
+}
+
+static int iommu_disable_translation(struct intel_iommu *iommu)
+{
+       u32 sts;
+       unsigned long flag;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       iommu->gcmd &= ~DMA_GCMD_TE;
+       writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
+
+       /* Make sure hardware complete it */
+       IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+               readl, (!(sts & DMA_GSTS_TES)), sts);
+
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+       return 0;
+}
+
+/* iommu interrupt handling. Most stuff are MSI-like. */
+
+static char *fault_reason_strings[] =
+{
+       "Software",
+       "Present bit in root entry is clear",
+       "Present bit in context entry is clear",
+       "Invalid context entry",
+       "Access beyond MGAW",
+       "PTE Write access is not set",
+       "PTE Read access is not set",
+       "Next page table ptr is invalid",
+       "Root table address invalid",
+       "Context table ptr is invalid",
+       "non-zero reserved fields in RTP",
+       "non-zero reserved fields in CTP",
+       "non-zero reserved fields in PTE",
+       "Unknown"
+};
+#define MAX_FAULT_REASON_IDX   ARRAY_SIZE(fault_reason_strings)
+
+char *dmar_get_fault_reason(u8 fault_reason)
+{
+       if (fault_reason > MAX_FAULT_REASON_IDX)
+               return fault_reason_strings[MAX_FAULT_REASON_IDX];
+       else
+               return fault_reason_strings[fault_reason];
+}
+
+void dmar_msi_unmask(unsigned int irq)
+{
+       struct intel_iommu *iommu = get_irq_data(irq);
+       unsigned long flag;
+
+       /* unmask it */
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       writel(0, iommu->reg + DMAR_FECTL_REG);
+       /* Read a reg to force flush the post write */
+       readl(iommu->reg + DMAR_FECTL_REG);
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_mask(unsigned int irq)
+{
+       unsigned long flag;
+       struct intel_iommu *iommu = get_irq_data(irq);
+
+       /* mask it */
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
+       /* Read a reg to force flush the post write */
+       readl(iommu->reg + DMAR_FECTL_REG);
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_write(int irq, struct msi_msg *msg)
+{
+       struct intel_iommu *iommu = get_irq_data(irq);
+       unsigned long flag;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
+       writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
+       writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_read(int irq, struct msi_msg *msg)
+{
+       struct intel_iommu *iommu = get_irq_data(irq);
+       unsigned long flag;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
+       msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
+       msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+static int iommu_page_fault_do_one(struct intel_iommu *iommu, int type,
+               u8 fault_reason, u16 source_id, u64 addr)
+{
+       char *reason;
+
+       reason = dmar_get_fault_reason(fault_reason);
+
+       printk(KERN_ERR
+               "DMAR:[%s] Request device [%02x:%02x.%d] "
+               "fault addr %llx \n"
+               "DMAR:[fault reason %02d] %s\n",
+               (type ? "DMA Read" : "DMA Write"),
+               (source_id >> 8), PCI_SLOT(source_id & 0xFF),
+               PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
+       return 0;
+}
+
+#define PRIMARY_FAULT_REG_LEN (16)
+static irqreturn_t iommu_page_fault(int irq, void *dev_id)
+{
+       struct intel_iommu *iommu = dev_id;
+       int reg, fault_index;
+       u32 fault_status;
+       unsigned long flag;
+
+       spin_lock_irqsave(&iommu->register_lock, flag);
+       fault_status = readl(iommu->reg + DMAR_FSTS_REG);
+
+       /* TBD: ignore advanced fault log currently */
+       if (!(fault_status & DMA_FSTS_PPF))
+               goto clear_overflow;
+
+       fault_index = dma_fsts_fault_record_index(fault_status);
+       reg = cap_fault_reg_offset(iommu->cap);
+       while (1) {
+               u8 fault_reason;
+               u16 source_id;
+               u64 guest_addr;
+               int type;
+               u32 data;
+
+               /* highest 32 bits */
+               data = readl(iommu->reg + reg +
+                               fault_index * PRIMARY_FAULT_REG_LEN + 12);
+               if (!(data & DMA_FRCD_F))
+                       break;
+
+               fault_reason = dma_frcd_fault_reason(data);
+               type = dma_frcd_type(data);
+
+               data = readl(iommu->reg + reg +
+                               fault_index * PRIMARY_FAULT_REG_LEN + 8);
+               source_id = dma_frcd_source_id(data);
+
+               guest_addr = dmar_readq(iommu->reg + reg +
+                               fault_index * PRIMARY_FAULT_REG_LEN);
+               guest_addr = dma_frcd_page_addr(guest_addr);
+               /* clear the fault */
+               writel(DMA_FRCD_F, iommu->reg + reg +
+                       fault_index * PRIMARY_FAULT_REG_LEN + 12);
+
+               spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+               iommu_page_fault_do_one(iommu, type, fault_reason,
+                               source_id, guest_addr);
+
+               fault_index++;
+               if (fault_index > cap_num_fault_regs(iommu->cap))
+                       fault_index = 0;
+               spin_lock_irqsave(&iommu->register_lock, flag);
+       }
+clear_overflow:
+       /* clear primary fault overflow */
+       fault_status = readl(iommu->reg + DMAR_FSTS_REG);
+       if (fault_status & DMA_FSTS_PFO)
+               writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
+
+       spin_unlock_irqrestore(&iommu->register_lock, flag);
+       return IRQ_HANDLED;
+}
+
+int dmar_set_interrupt(struct intel_iommu *iommu)
+{
+       int irq, ret;
+
+       irq = create_irq();
+       if (!irq) {
+               printk(KERN_ERR "IOMMU: no free vectors\n");
+               return -EINVAL;
+       }
+
+       set_irq_data(irq, iommu);
+       iommu->irq = irq;
+
+       ret = arch_setup_dmar_msi(irq);
+       if (ret) {
+               set_irq_data(irq, NULL);
+               iommu->irq = 0;
+               destroy_irq(irq);
+               return 0;
+       }
+
+       /* Force fault register is cleared */
+       iommu_page_fault(irq, iommu);
+
+       ret = request_irq(irq, iommu_page_fault, 0, iommu->name, iommu);
+       if (ret)
+               printk(KERN_ERR "IOMMU: can't request irq\n");
+       return ret;
+}
+
+static int iommu_init_domains(struct intel_iommu *iommu)
+{
+       unsigned long ndomains;
+       unsigned long nlongs;
+
+       ndomains = cap_ndoms(iommu->cap);
+       pr_debug("Number of Domains supportd <%ld>\n", ndomains);
+       nlongs = BITS_TO_LONGS(ndomains);
+
+       /* TBD: there might be 64K domains,
+        * consider other allocation for future chip
+        */
+       iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
+       if (!iommu->domain_ids) {
+               printk(KERN_ERR "Allocating domain id array failed\n");
+               return -ENOMEM;
+       }
+       iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
+                       GFP_KERNEL);
+       if (!iommu->domains) {
+               printk(KERN_ERR "Allocating domain array failed\n");
+               kfree(iommu->domain_ids);
+               return -ENOMEM;
+       }
+
+       /*
+        * if Caching mode is set, then invalid translations are tagged
+        * with domainid 0. Hence we need to pre-allocate it.
+        */
+       if (cap_caching_mode(iommu->cap))
+               set_bit(0, iommu->domain_ids);
+       return 0;
+}
+
+static struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd)
+{
+       struct intel_iommu *iommu;
+       int ret;
+       int map_size;
+       u32 ver;
+
+       iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+       if (!iommu)
+               return NULL;
+       iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K);
+       if (!iommu->reg) {
+               printk(KERN_ERR "IOMMU: can't map the region\n");
+               goto error;
+       }
+       iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
+       iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
+
+       /* the registers might be more than one page */
+       map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
+               cap_max_fault_reg_offset(iommu->cap));
+       map_size = PAGE_ALIGN_4K(map_size);
+       if (map_size > PAGE_SIZE_4K) {
+               iounmap(iommu->reg);
+               iommu->reg = ioremap(drhd->reg_base_addr, map_size);
+               if (!iommu->reg) {
+                       printk(KERN_ERR "IOMMU: can't map the region\n");
+                       goto error;
+               }
+       }
+
+       ver = readl(iommu->reg + DMAR_VER_REG);
+       pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
+               drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
+               iommu->cap, iommu->ecap);
+       ret = iommu_init_domains(iommu);
+       if (ret)
+               goto error_unmap;
+       spin_lock_init(&iommu->lock);
+       spin_lock_init(&iommu->register_lock);
+
+       drhd->iommu = iommu;
+       return iommu;
+error_unmap:
+       iounmap(iommu->reg);
+       iommu->reg = 0;
+error:
+       kfree(iommu);
+       return NULL;
+}
+
+static void domain_exit(struct dmar_domain *domain);
+static void free_iommu(struct intel_iommu *iommu)
+{
+       struct dmar_domain *domain;
+       int i;
+
+       if (!iommu)
+               return;
+
+       i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
+       for (; i < cap_ndoms(iommu->cap); ) {
+               domain = iommu->domains[i];
+               clear_bit(i, iommu->domain_ids);
+               domain_exit(domain);
+               i = find_next_bit(iommu->domain_ids,
+                       cap_ndoms(iommu->cap), i+1);
+       }
+
+       if (iommu->gcmd & DMA_GCMD_TE)
+               iommu_disable_translation(iommu);
+
+       if (iommu->irq) {
+               set_irq_data(iommu->irq, NULL);
+               /* This will mask the irq */
+               free_irq(iommu->irq, iommu);
+               destroy_irq(iommu->irq);
+       }
+
+       kfree(iommu->domains);
+       kfree(iommu->domain_ids);
+
+       /* free context mapping */
+       free_context_table(iommu);
+
+       if (iommu->reg)
+               iounmap(iommu->reg);
+       kfree(iommu);
+}
+
+static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
+{
+       unsigned long num;
+       unsigned long ndomains;
+       struct dmar_domain *domain;
+       unsigned long flags;
+
+       domain = alloc_domain_mem();
+       if (!domain)
+               return NULL;
+
+       ndomains = cap_ndoms(iommu->cap);
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       num = find_first_zero_bit(iommu->domain_ids, ndomains);
+       if (num >= ndomains) {
+               spin_unlock_irqrestore(&iommu->lock, flags);
+               free_domain_mem(domain);
+               printk(KERN_ERR "IOMMU: no free domain ids\n");
+               return NULL;
+       }
+
+       set_bit(num, iommu->domain_ids);
+       domain->id = num;
+       domain->iommu = iommu;
+       iommu->domains[num] = domain;
+       spin_unlock_irqrestore(&iommu->lock, flags);
+
+       return domain;
+}
+
+static void iommu_free_domain(struct dmar_domain *domain)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&domain->iommu->lock, flags);
+       clear_bit(domain->id, domain->iommu->domain_ids);
+       spin_unlock_irqrestore(&domain->iommu->lock, flags);
+}
+
+static struct iova_domain reserved_iova_list;
+
+static void dmar_init_reserved_ranges(void)
+{
+       struct pci_dev *pdev = NULL;
+       struct iova *iova;
+       int i;
+       u64 addr, size;
+
+       init_iova_domain(&reserved_iova_list);
+
+       /* IOAPIC ranges shouldn't be accessed by DMA */
+       iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
+               IOVA_PFN(IOAPIC_RANGE_END));
+       if (!iova)
+               printk(KERN_ERR "Reserve IOAPIC range failed\n");
+
+       /* Reserve all PCI MMIO to avoid peer-to-peer access */
+       for_each_pci_dev(pdev) {
+               struct resource *r;
+
+               for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+                       r = &pdev->resource[i];
+                       if (!r->flags || !(r->flags & IORESOURCE_MEM))
+                               continue;
+                       addr = r->start;
+                       addr &= PAGE_MASK_4K;
+                       size = r->end - addr;
+                       size = PAGE_ALIGN_4K(size);
+                       iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
+                               IOVA_PFN(size + addr) - 1);
+                       if (!iova)
+                               printk(KERN_ERR "Reserve iova failed\n");
+               }
+       }
+
+}
+
+static void domain_reserve_special_ranges(struct dmar_domain *domain)
+{
+       copy_reserved_iova(&reserved_iova_list, &domain->iovad);
+}
+
+static inline int guestwidth_to_adjustwidth(int gaw)
+{
+       int agaw;
+       int r = (gaw - 12) % 9;
+
+       if (r == 0)
+               agaw = gaw;
+       else
+               agaw = gaw + 9 - r;
+       if (agaw > 64)
+               agaw = 64;
+       return agaw;
+}
+
+static int domain_init(struct dmar_domain *domain, int guest_width)
+{
+       struct intel_iommu *iommu;
+       int adjust_width, agaw;
+       unsigned long sagaw;
+
+       init_iova_domain(&domain->iovad);
+       spin_lock_init(&domain->mapping_lock);
+
+       domain_reserve_special_ranges(domain);
+
+       /* calculate AGAW */
+       iommu = domain->iommu;
+       if (guest_width > cap_mgaw(iommu->cap))
+               guest_width = cap_mgaw(iommu->cap);
+       domain->gaw = guest_width;
+       adjust_width = guestwidth_to_adjustwidth(guest_width);
+       agaw = width_to_agaw(adjust_width);
+       sagaw = cap_sagaw(iommu->cap);
+       if (!test_bit(agaw, &sagaw)) {
+               /* hardware doesn't support it, choose a bigger one */
+               pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
+               agaw = find_next_bit(&sagaw, 5, agaw);
+               if (agaw >= 5)
+                       return -ENODEV;
+       }
+       domain->agaw = agaw;
+       INIT_LIST_HEAD(&domain->devices);
+
+       /* always allocate the top pgd */
+       domain->pgd = (struct dma_pte *)alloc_pgtable_page();
+       if (!domain->pgd)
+               return -ENOMEM;
+       __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE_4K);
+       return 0;
+}
+
+static void domain_exit(struct dmar_domain *domain)
+{
+       u64 end;
+
+       /* Domain 0 is reserved, so dont process it */
+       if (!domain)
+               return;
+
+       domain_remove_dev_info(domain);
+       /* destroy iovas */
+       put_iova_domain(&domain->iovad);
+       end = DOMAIN_MAX_ADDR(domain->gaw);
+       end = end & (~PAGE_MASK_4K);
+
+       /* clear ptes */
+       dma_pte_clear_range(domain, 0, end);
+
+       /* free page tables */
+       dma_pte_free_pagetable(domain, 0, end);
+
+       iommu_free_domain(domain);
+       free_domain_mem(domain);
+}
+
+static int domain_context_mapping_one(struct dmar_domain *domain,
+               u8 bus, u8 devfn)
+{
+       struct context_entry *context;
+       struct intel_iommu *iommu = domain->iommu;
+       unsigned long flags;
+
+       pr_debug("Set context mapping for %02x:%02x.%d\n",
+               bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+       BUG_ON(!domain->pgd);
+       context = device_to_context_entry(iommu, bus, devfn);
+       if (!context)
+               return -ENOMEM;
+       spin_lock_irqsave(&iommu->lock, flags);
+       if (context_present(*context)) {
+               spin_unlock_irqrestore(&iommu->lock, flags);
+               return 0;
+       }
+
+       context_set_domain_id(*context, domain->id);
+       context_set_address_width(*context, domain->agaw);
+       context_set_address_root(*context, virt_to_phys(domain->pgd));
+       context_set_translation_type(*context, CONTEXT_TT_MULTI_LEVEL);
+       context_set_fault_enable(*context);
+       context_set_present(*context);
+       __iommu_flush_cache(iommu, context, sizeof(*context));
+
+       /* it's a non-present to present mapping */
+       if (iommu_flush_context_device(iommu, domain->id,
+                       (((u16)bus) << 8) | devfn, DMA_CCMD_MASK_NOBIT, 1))
+               iommu_flush_write_buffer(iommu);
+       else
+               iommu_flush_iotlb_dsi(iommu, 0, 0);
+       spin_unlock_irqrestore(&iommu->lock, flags);
+       return 0;
+}
+
+static int
+domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev)
+{
+       int ret;
+       struct pci_dev *tmp, *parent;
+
+       ret = domain_context_mapping_one(domain, pdev->bus->number,
+               pdev->devfn);
+       if (ret)
+               return ret;
+
+       /* dependent device mapping */
+       tmp = pci_find_upstream_pcie_bridge(pdev);
+       if (!tmp)
+               return 0;
+       /* Secondary interface's bus number and devfn 0 */
+       parent = pdev->bus->self;
+       while (parent != tmp) {
+               ret = domain_context_mapping_one(domain, parent->bus->number,
+                       parent->devfn);
+               if (ret)
+                       return ret;
+               parent = parent->bus->self;
+       }
+       if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
+               return domain_context_mapping_one(domain,
+                       tmp->subordinate->number, 0);
+       else /* this is a legacy PCI bridge */
+               return domain_context_mapping_one(domain,
+                       tmp->bus->number, tmp->devfn);
+}
+
+static int domain_context_mapped(struct dmar_domain *domain,
+       struct pci_dev *pdev)
+{
+       int ret;
+       struct pci_dev *tmp, *parent;
+
+       ret = device_context_mapped(domain->iommu,
+               pdev->bus->number, pdev->devfn);
+       if (!ret)
+               return ret;
+       /* dependent device mapping */
+       tmp = pci_find_upstream_pcie_bridge(pdev);
+       if (!tmp)
+               return ret;
+       /* Secondary interface's bus number and devfn 0 */
+       parent = pdev->bus->self;
+       while (parent != tmp) {
+               ret = device_context_mapped(domain->iommu, parent->bus->number,
+                       parent->devfn);
+               if (!ret)
+                       return ret;
+               parent = parent->bus->self;
+       }
+       if (tmp->is_pcie)
+               return device_context_mapped(domain->iommu,
+                       tmp->subordinate->number, 0);
+       else
+               return device_context_mapped(domain->iommu,
+                       tmp->bus->number, tmp->devfn);
+}
+
+static int
+domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
+                       u64 hpa, size_t size, int prot)
+{
+       u64 start_pfn, end_pfn;
+       struct dma_pte *pte;
+       int index;
+
+       if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
+               return -EINVAL;
+       iova &= PAGE_MASK_4K;
+       start_pfn = ((u64)hpa) >> PAGE_SHIFT_4K;
+       end_pfn = (PAGE_ALIGN_4K(((u64)hpa) + size)) >> PAGE_SHIFT_4K;
+       index = 0;
+       while (start_pfn < end_pfn) {
+               pte = addr_to_dma_pte(domain, iova + PAGE_SIZE_4K * index);
+               if (!pte)
+                       return -ENOMEM;
+               /* We don't need lock here, nobody else
+                * touches the iova range
+                */
+               BUG_ON(dma_pte_addr(*pte));
+               dma_set_pte_addr(*pte, start_pfn << PAGE_SHIFT_4K);
+               dma_set_pte_prot(*pte, prot);
+               __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+               start_pfn++;
+               index++;
+       }
+       return 0;
+}
+
+static void detach_domain_for_dev(struct dmar_domain *domain, u8 bus, u8 devfn)
+{
+       clear_context_table(domain->iommu, bus, devfn);
+       iommu_flush_context_global(domain->iommu, 0);
+       iommu_flush_iotlb_global(domain->iommu, 0);
+}
+
+static void domain_remove_dev_info(struct dmar_domain *domain)
+{
+       struct device_domain_info *info;
+       unsigned long flags;
+
+       spin_lock_irqsave(&device_domain_lock, flags);
+       while (!list_empty(&domain->devices)) {
+               info = list_entry(domain->devices.next,
+                       struct device_domain_info, link);
+               list_del(&info->link);
+               list_del(&info->global);
+               if (info->dev)
+                       info->dev->dev.archdata.iommu = NULL;
+               spin_unlock_irqrestore(&device_domain_lock, flags);
+
+               detach_domain_for_dev(info->domain, info->bus, info->devfn);
+               free_devinfo_mem(info);
+
+               spin_lock_irqsave(&device_domain_lock, flags);
+       }
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+}
+
+/*
+ * find_domain
+ * Note: we use struct pci_dev->dev.archdata.iommu stores the info
+ */
+struct dmar_domain *
+find_domain(struct pci_dev *pdev)
+{
+       struct device_domain_info *info;
+
+       /* No lock here, assumes no domain exit in normal case */
+       info = pdev->dev.archdata.iommu;
+       if (info)
+               return info->domain;
+       return NULL;
+}
+
+static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
+     struct pci_dev *dev)
+{
+       int index;
+
+       while (dev) {
+               for (index = 0; index < cnt; index ++)
+                       if (dev == devices[index])
+                               return 1;
+
+               /* Check our parent */
+               dev = dev->bus->self;
+       }
+
+       return 0;
+}
+
+static struct dmar_drhd_unit *
+dmar_find_matched_drhd_unit(struct pci_dev *dev)
+{
+       struct dmar_drhd_unit *drhd = NULL;
+
+       list_for_each_entry(drhd, &dmar_drhd_units, list) {
+               if (drhd->include_all || dmar_pci_device_match(drhd->devices,
+                                               drhd->devices_cnt, dev))
+                       return drhd;
+       }
+
+       return NULL;
+}
+
+/* domain is initialized */
+static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
+{
+       struct dmar_domain *domain, *found = NULL;
+       struct intel_iommu *iommu;
+       struct dmar_drhd_unit *drhd;
+       struct device_domain_info *info, *tmp;
+       struct pci_dev *dev_tmp;
+       unsigned long flags;
+       int bus = 0, devfn = 0;
+
+       domain = find_domain(pdev);
+       if (domain)
+               return domain;
+
+       dev_tmp = pci_find_upstream_pcie_bridge(pdev);
+       if (dev_tmp) {
+               if (dev_tmp->is_pcie) {
+                       bus = dev_tmp->subordinate->number;
+                       devfn = 0;
+               } else {
+                       bus = dev_tmp->bus->number;
+                       devfn = dev_tmp->devfn;
+               }
+               spin_lock_irqsave(&device_domain_lock, flags);
+               list_for_each_entry(info, &device_domain_list, global) {
+                       if (info->bus == bus && info->devfn == devfn) {
+                               found = info->domain;
+                               break;
+                       }
+               }
+               spin_unlock_irqrestore(&device_domain_lock, flags);
+               /* pcie-pci bridge already has a domain, uses it */
+               if (found) {
+                       domain = found;
+                       goto found_domain;
+               }
+       }
+
+       /* Allocate new domain for the device */
+       drhd = dmar_find_matched_drhd_unit(pdev);
+       if (!drhd) {
+               printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
+                       pci_name(pdev));
+               return NULL;
+       }
+       iommu = drhd->iommu;
+
+       domain = iommu_alloc_domain(iommu);
+       if (!domain)
+               goto error;
+
+       if (domain_init(domain, gaw)) {
+               domain_exit(domain);
+               goto error;
+       }
+
+       /* register pcie-to-pci device */
+       if (dev_tmp) {
+               info = alloc_devinfo_mem();
+               if (!info) {
+                       domain_exit(domain);
+                       goto error;
+               }
+               info->bus = bus;
+               info->devfn = devfn;
+               info->dev = NULL;
+               info->domain = domain;
+               /* This domain is shared by devices under p2p bridge */
+               domain->flags |= DOMAIN_FLAG_MULTIPLE_DEVICES;
+
+               /* pcie-to-pci bridge already has a domain, uses it */
+               found = NULL;
+               spin_lock_irqsave(&device_domain_lock, flags);
+               list_for_each_entry(tmp, &device_domain_list, global) {
+                       if (tmp->bus == bus && tmp->devfn == devfn) {
+                               found = tmp->domain;
+                               break;
+                       }
+               }
+               if (found) {
+                       free_devinfo_mem(info);
+                       domain_exit(domain);
+                       domain = found;
+               } else {
+                       list_add(&info->link, &domain->devices);
+                       list_add(&info->global, &device_domain_list);
+               }
+               spin_unlock_irqrestore(&device_domain_lock, flags);
+       }
+
+found_domain:
+       info = alloc_devinfo_mem();
+       if (!info)
+               goto error;
+       info->bus = pdev->bus->number;
+       info->devfn = pdev->devfn;
+       info->dev = pdev;
+       info->domain = domain;
+       spin_lock_irqsave(&device_domain_lock, flags);
+       /* somebody is fast */
+       found = find_domain(pdev);
+       if (found != NULL) {
+               spin_unlock_irqrestore(&device_domain_lock, flags);
+               if (found != domain) {
+                       domain_exit(domain);
+                       domain = found;
+               }
+               free_devinfo_mem(info);
+               return domain;
+       }
+       list_add(&info->link, &domain->devices);
+       list_add(&info->global, &device_domain_list);
+       pdev->dev.archdata.iommu = info;
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+       return domain;
+error:
+       /* recheck it here, maybe others set it */
+       return find_domain(pdev);
+}
+
+static int iommu_prepare_identity_map(struct pci_dev *pdev, u64 start, u64 end)
+{
+       struct dmar_domain *domain;
+       unsigned long size;
+       u64 base;
+       int ret;
+
+       printk(KERN_INFO
+               "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
+               pci_name(pdev), start, end);
+       /* page table init */
+       domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
+       if (!domain)
+               return -ENOMEM;
+
+       /* The address might not be aligned */
+       base = start & PAGE_MASK_4K;
+       size = end - base;
+       size = PAGE_ALIGN_4K(size);
+       if (!reserve_iova(&domain->iovad, IOVA_PFN(base),
+                       IOVA_PFN(base + size) - 1)) {
+               printk(KERN_ERR "IOMMU: reserve iova failed\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       pr_debug("Mapping reserved region %lx@%llx for %s\n",
+               size, base, pci_name(pdev));
+       /*
+        * RMRR range might have overlap with physical memory range,
+        * clear it first
+        */
+       dma_pte_clear_range(domain, base, base + size);
+
+       ret = domain_page_mapping(domain, base, base, size,
+               DMA_PTE_READ|DMA_PTE_WRITE);
+       if (ret)
+               goto error;
+
+       /* context entry init */
+       ret = domain_context_mapping(domain, pdev);
+       if (!ret)
+               return 0;
+error:
+       domain_exit(domain);
+       return ret;
+
+}
+
+static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
+       struct pci_dev *pdev)
+{
+       if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+               return 0;
+       return iommu_prepare_identity_map(pdev, rmrr->base_address,
+               rmrr->end_address + 1);
+}
+
+#ifdef CONFIG_DMAR_GFX_WA
+extern int arch_get_ram_range(int slot, u64 *addr, u64 *size);
+static void __init iommu_prepare_gfx_mapping(void)
+{
+       struct pci_dev *pdev = NULL;
+       u64 base, size;
+       int slot;
+       int ret;
+
+       for_each_pci_dev(pdev) {
+               if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO ||
+                               !IS_GFX_DEVICE(pdev))
+                       continue;
+               printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
+                       pci_name(pdev));
+               slot = arch_get_ram_range(0, &base, &size);
+               while (slot >= 0) {
+                       ret = iommu_prepare_identity_map(pdev,
+                                       base, base + size);
+                       if (ret)
+                               goto error;
+                       slot = arch_get_ram_range(slot, &base, &size);
+               }
+               continue;
+error:
+               printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
+       }
+}
+#endif
+
+#ifdef CONFIG_DMAR_FLOPPY_WA
+static inline void iommu_prepare_isa(void)
+{
+       struct pci_dev *pdev;
+       int ret;
+
+       pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
+       if (!pdev)
+               return;
+
+       printk(KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n");
+       ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
+
+       if (ret)
+               printk("IOMMU: Failed to create 0-64M identity map, "
+                       "floppy might not work\n");
+
+}
+#else
+static inline void iommu_prepare_isa(void)
+{
+       return;
+}
+#endif /* !CONFIG_DMAR_FLPY_WA */
+
+int __init init_dmars(void)
+{
+       struct dmar_drhd_unit *drhd;
+       struct dmar_rmrr_unit *rmrr;
+       struct pci_dev *pdev;
+       struct intel_iommu *iommu;
+       int ret, unit = 0;
+
+       /*
+        * for each drhd
+        *    allocate root
+        *    initialize and program root entry to not present
+        * endfor
+        */
+       for_each_drhd_unit(drhd) {
+               if (drhd->ignored)
+                       continue;
+               iommu = alloc_iommu(drhd);
+               if (!iommu) {
+                       ret = -ENOMEM;
+                       goto error;
+               }
+
+               /*
+                * TBD:
+                * we could share the same root & context tables
+                * amoung all IOMMU's. Need to Split it later.
+                */
+               ret = iommu_alloc_root_entry(iommu);
+               if (ret) {
+                       printk(KERN_ERR "IOMMU: allocate root entry failed\n");
+                       goto error;
+               }
+       }
+
+       /*
+        * For each rmrr
+        *   for each dev attached to rmrr
+        *   do
+        *     locate drhd for dev, alloc domain for dev
+        *     allocate free domain
+        *     allocate page table entries for rmrr
+        *     if context not allocated for bus
+        *           allocate and init context
+        *           set present in root table for this bus
+        *     init context with domain, translation etc
+        *    endfor
+        * endfor
+        */
+       for_each_rmrr_units(rmrr) {
+               int i;
+               for (i = 0; i < rmrr->devices_cnt; i++) {
+                       pdev = rmrr->devices[i];
+                       /* some BIOS lists non-exist devices in DMAR table */
+                       if (!pdev)
+                               continue;
+                       ret = iommu_prepare_rmrr_dev(rmrr, pdev);
+                       if (ret)
+                               printk(KERN_ERR
+                                "IOMMU: mapping reserved region failed\n");
+               }
+       }
+
+       iommu_prepare_gfx_mapping();
+
+       iommu_prepare_isa();
+
+       /*
+        * for each drhd
+        *   enable fault log
+        *   global invalidate context cache
+        *   global invalidate iotlb
+        *   enable translation
+        */
+       for_each_drhd_unit(drhd) {
+               if (drhd->ignored)
+                       continue;
+               iommu = drhd->iommu;
+               sprintf (iommu->name, "dmar%d", unit++);
+
+               iommu_flush_write_buffer(iommu);
+
+               ret = dmar_set_interrupt(iommu);
+               if (ret)
+                       goto error;
+
+               iommu_set_root_entry(iommu);
+
+               iommu_flush_context_global(iommu, 0);
+               iommu_flush_iotlb_global(iommu, 0);
+
+               ret = iommu_enable_translation(iommu);
+               if (ret)
+                       goto error;
+       }
+
+       return 0;
+error:
+       for_each_drhd_unit(drhd) {
+               if (drhd->ignored)
+                       continue;
+               iommu = drhd->iommu;
+               free_iommu(iommu);
+       }
+       return ret;
+}
+
+static inline u64 aligned_size(u64 host_addr, size_t size)
+{
+       u64 addr;
+       addr = (host_addr & (~PAGE_MASK_4K)) + size;
+       return PAGE_ALIGN_4K(addr);
+}
+
+struct iova *
+iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
+{
+       struct iova *piova;
+
+       /* Make sure it's in range */
+       end = min_t(u64, DOMAIN_MAX_ADDR(domain->gaw), end);
+       if (!size || (IOVA_START_ADDR + size > end))
+               return NULL;
+
+       piova = alloc_iova(&domain->iovad,
+                       size >> PAGE_SHIFT_4K, IOVA_PFN(end), 1);
+       return piova;
+}
+
+static struct iova *
+__intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
+               size_t size)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct iova *iova = NULL;
+
+       if ((pdev->dma_mask <= DMA_32BIT_MASK) || (dmar_forcedac)) {
+               iova = iommu_alloc_iova(domain, size, pdev->dma_mask);
+       } else  {
+               /*
+                * First try to allocate an io virtual address in
+                * DMA_32BIT_MASK and if that fails then try allocating
+                * from higer range
+                */
+               iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK);
+               if (!iova)
+                       iova = iommu_alloc_iova(domain, size, pdev->dma_mask);
+       }
+
+       if (!iova) {
+               printk(KERN_ERR"Allocating iova for %s failed", pci_name(pdev));
+               return NULL;
+       }
+
+       return iova;
+}
+
+static struct dmar_domain *
+get_valid_domain_for_dev(struct pci_dev *pdev)
+{
+       struct dmar_domain *domain;
+       int ret;
+
+       domain = get_domain_for_dev(pdev,
+                       DEFAULT_DOMAIN_ADDRESS_WIDTH);
+       if (!domain) {
+               printk(KERN_ERR
+                       "Allocating domain for %s failed", pci_name(pdev));
+               return 0;
+       }
+
+       /* make sure context mapping is ok */
+       if (unlikely(!domain_context_mapped(domain, pdev))) {
+               ret = domain_context_mapping(domain, pdev);
+               if (ret) {
+                       printk(KERN_ERR
+                               "Domain context map for %s failed",
+                               pci_name(pdev));
+                       return 0;
+               }
+       }
+
+       return domain;
+}
+
+static dma_addr_t intel_map_single(struct device *hwdev, void *addr,
+       size_t size, int dir)
+{
+       struct pci_dev *pdev = to_pci_dev(hwdev);
+       int ret;
+       struct dmar_domain *domain;
+       unsigned long start_addr;
+       struct iova *iova;
+       int prot = 0;
+
+       BUG_ON(dir == DMA_NONE);
+       if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+               return virt_to_bus(addr);
+
+       domain = get_valid_domain_for_dev(pdev);
+       if (!domain)
+               return 0;
+
+       addr = (void *)virt_to_phys(addr);
+       size = aligned_size((u64)addr, size);
+
+       iova = __intel_alloc_iova(hwdev, domain, size);
+       if (!iova)
+               goto error;
+
+       start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+
+       /*
+        * Check if DMAR supports zero-length reads on write only
+        * mappings..
+        */
+       if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
+                       !cap_zlr(domain->iommu->cap))
+               prot |= DMA_PTE_READ;
+       if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
+               prot |= DMA_PTE_WRITE;
+       /*
+        * addr - (addr + size) might be partial page, we should map the whole
+        * page.  Note: if two part of one page are separately mapped, we
+        * might have two guest_addr mapping to the same host addr, but this
+        * is not a big problem
+        */
+       ret = domain_page_mapping(domain, start_addr,
+               ((u64)addr) & PAGE_MASK_4K, size, prot);
+       if (ret)
+               goto error;
+
+       pr_debug("Device %s request: %lx@%llx mapping: %lx@%llx, dir %d\n",
+               pci_name(pdev), size, (u64)addr,
+               size, (u64)start_addr, dir);
+
+       /* it's a non-present to present mapping */
+       ret = iommu_flush_iotlb_psi(domain->iommu, domain->id,
+                       start_addr, size >> PAGE_SHIFT_4K, 1);
+       if (ret)
+               iommu_flush_write_buffer(domain->iommu);
+
+       return (start_addr + ((u64)addr & (~PAGE_MASK_4K)));
+
+error:
+       if (iova)
+               __free_iova(&domain->iovad, iova);
+       printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n",
+               pci_name(pdev), size, (u64)addr, dir);
+       return 0;
+}
+
+static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
+       size_t size, int dir)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct dmar_domain *domain;
+       unsigned long start_addr;
+       struct iova *iova;
+
+       if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+               return;
+       domain = find_domain(pdev);
+       BUG_ON(!domain);
+
+       iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
+       if (!iova)
+               return;
+
+       start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+       size = aligned_size((u64)dev_addr, size);
+
+       pr_debug("Device %s unmapping: %lx@%llx\n",
+               pci_name(pdev), size, (u64)start_addr);
+
+       /*  clear the whole page */
+       dma_pte_clear_range(domain, start_addr, start_addr + size);
+       /* free page tables */
+       dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+
+       if (iommu_flush_iotlb_psi(domain->iommu, domain->id, start_addr,
+                       size >> PAGE_SHIFT_4K, 0))
+               iommu_flush_write_buffer(domain->iommu);
+
+       /* free iova */
+       __free_iova(&domain->iovad, iova);
+}
+
+static void * intel_alloc_coherent(struct device *hwdev, size_t size,
+                      dma_addr_t *dma_handle, gfp_t flags)
+{
+       void *vaddr;
+       int order;
+
+       size = PAGE_ALIGN_4K(size);
+       order = get_order(size);
+       flags &= ~(GFP_DMA | GFP_DMA32);
+
+       vaddr = (void *)__get_free_pages(flags, order);
+       if (!vaddr)
+               return NULL;
+       memset(vaddr, 0, size);
+
+       *dma_handle = intel_map_single(hwdev, vaddr, size, DMA_BIDIRECTIONAL);
+       if (*dma_handle)
+               return vaddr;
+       free_pages((unsigned long)vaddr, order);
+       return NULL;
+}
+
+static void intel_free_coherent(struct device *hwdev, size_t size,
+       void *vaddr, dma_addr_t dma_handle)
+{
+       int order;
+
+       size = PAGE_ALIGN_4K(size);
+       order = get_order(size);
+
+       intel_unmap_single(hwdev, dma_handle, size, DMA_BIDIRECTIONAL);
+       free_pages((unsigned long)vaddr, order);
+}
+
+#define SG_ENT_VIRT_ADDRESS(sg)        (sg_virt((sg)))
+static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
+       int nelems, int dir)
+{
+       int i;
+       struct pci_dev *pdev = to_pci_dev(hwdev);
+       struct dmar_domain *domain;
+       unsigned long start_addr;
+       struct iova *iova;
+       size_t size = 0;
+       void *addr;
+       struct scatterlist *sg;
+
+       if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+               return;
+
+       domain = find_domain(pdev);
+
+       iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
+       if (!iova)
+               return;
+       for_each_sg(sglist, sg, nelems, i) {
+               addr = SG_ENT_VIRT_ADDRESS(sg);
+               size += aligned_size((u64)addr, sg->length);
+       }
+
+       start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+
+       /*  clear the whole page */
+       dma_pte_clear_range(domain, start_addr, start_addr + size);
+       /* free page tables */
+       dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+
+       if (iommu_flush_iotlb_psi(domain->iommu, domain->id, start_addr,
+                       size >> PAGE_SHIFT_4K, 0))
+               iommu_flush_write_buffer(domain->iommu);
+
+       /* free iova */
+       __free_iova(&domain->iovad, iova);
+}
+
+static int intel_nontranslate_map_sg(struct device *hddev,
+       struct scatterlist *sglist, int nelems, int dir)
+{
+       int i;
+       struct scatterlist *sg;
+
+       for_each_sg(sglist, sg, nelems, i) {
+               BUG_ON(!sg_page(sg));
+               sg->dma_address = virt_to_bus(SG_ENT_VIRT_ADDRESS(sg));
+               sg->dma_length = sg->length;
+       }
+       return nelems;
+}
+
+static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist,
+                               int nelems, int dir)
+{
+       void *addr;
+       int i;
+       struct pci_dev *pdev = to_pci_dev(hwdev);
+       struct dmar_domain *domain;
+       size_t size = 0;
+       int prot = 0;
+       size_t offset = 0;
+       struct iova *iova = NULL;
+       int ret;
+       struct scatterlist *sg;
+       unsigned long start_addr;
+
+       BUG_ON(dir == DMA_NONE);
+       if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+               return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
+
+       domain = get_valid_domain_for_dev(pdev);
+       if (!domain)
+               return 0;
+
+       for_each_sg(sglist, sg, nelems, i) {
+               addr = SG_ENT_VIRT_ADDRESS(sg);
+               addr = (void *)virt_to_phys(addr);
+               size += aligned_size((u64)addr, sg->length);
+       }
+
+       iova = __intel_alloc_iova(hwdev, domain, size);
+       if (!iova) {
+               sglist->dma_length = 0;
+               return 0;
+       }
+
+       /*
+        * Check if DMAR supports zero-length reads on write only
+        * mappings..
+        */
+       if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
+                       !cap_zlr(domain->iommu->cap))
+               prot |= DMA_PTE_READ;
+       if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
+               prot |= DMA_PTE_WRITE;
+
+       start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+       offset = 0;
+       for_each_sg(sglist, sg, nelems, i) {
+               addr = SG_ENT_VIRT_ADDRESS(sg);
+               addr = (void *)virt_to_phys(addr);
+               size = aligned_size((u64)addr, sg->length);
+               ret = domain_page_mapping(domain, start_addr + offset,
+                       ((u64)addr) & PAGE_MASK_4K,
+                       size, prot);
+               if (ret) {
+                       /*  clear the page */
+                       dma_pte_clear_range(domain, start_addr,
+                                 start_addr + offset);
+                       /* free page tables */
+                       dma_pte_free_pagetable(domain, start_addr,
+                                 start_addr + offset);
+                       /* free iova */
+                       __free_iova(&domain->iovad, iova);
+                       return 0;
+               }
+               sg->dma_address = start_addr + offset +
+                               ((u64)addr & (~PAGE_MASK_4K));
+               sg->dma_length = sg->length;
+               offset += size;
+       }
+
+       /* it's a non-present to present mapping */
+       if (iommu_flush_iotlb_psi(domain->iommu, domain->id,
+                       start_addr, offset >> PAGE_SHIFT_4K, 1))
+               iommu_flush_write_buffer(domain->iommu);
+       return nelems;
+}
+
+static struct dma_mapping_ops intel_dma_ops = {
+       .alloc_coherent = intel_alloc_coherent,
+       .free_coherent = intel_free_coherent,
+       .map_single = intel_map_single,
+       .unmap_single = intel_unmap_single,
+       .map_sg = intel_map_sg,
+       .unmap_sg = intel_unmap_sg,
+};
+
+static inline int iommu_domain_cache_init(void)
+{
+       int ret = 0;
+
+       iommu_domain_cache = kmem_cache_create("iommu_domain",
+                                        sizeof(struct dmar_domain),
+                                        0,
+                                        SLAB_HWCACHE_ALIGN,
+
+                                        NULL);
+       if (!iommu_domain_cache) {
+               printk(KERN_ERR "Couldn't create iommu_domain cache\n");
+               ret = -ENOMEM;
+       }
+
+       return ret;
+}
+
+static inline int iommu_devinfo_cache_init(void)
+{
+       int ret = 0;
+
+       iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
+                                        sizeof(struct device_domain_info),
+                                        0,
+                                        SLAB_HWCACHE_ALIGN,
+
+                                        NULL);
+       if (!iommu_devinfo_cache) {
+               printk(KERN_ERR "Couldn't create devinfo cache\n");
+               ret = -ENOMEM;
+       }
+
+       return ret;
+}
+
+static inline int iommu_iova_cache_init(void)
+{
+       int ret = 0;
+
+       iommu_iova_cache = kmem_cache_create("iommu_iova",
+                                        sizeof(struct iova),
+                                        0,
+                                        SLAB_HWCACHE_ALIGN,
+
+                                        NULL);
+       if (!iommu_iova_cache) {
+               printk(KERN_ERR "Couldn't create iova cache\n");
+               ret = -ENOMEM;
+       }
+
+       return ret;
+}
+
+static int __init iommu_init_mempool(void)
+{
+       int ret;
+       ret = iommu_iova_cache_init();
+       if (ret)
+               return ret;
+
+       ret = iommu_domain_cache_init();
+       if (ret)
+               goto domain_error;
+
+       ret = iommu_devinfo_cache_init();
+       if (!ret)
+               return ret;
+
+       kmem_cache_destroy(iommu_domain_cache);
+domain_error:
+       kmem_cache_destroy(iommu_iova_cache);
+
+       return -ENOMEM;
+}
+
+static void __init iommu_exit_mempool(void)
+{
+       kmem_cache_destroy(iommu_devinfo_cache);
+       kmem_cache_destroy(iommu_domain_cache);
+       kmem_cache_destroy(iommu_iova_cache);
+
+}
+
+void __init detect_intel_iommu(void)
+{
+       if (swiotlb || no_iommu || iommu_detected || dmar_disabled)
+               return;
+       if (early_dmar_detect()) {
+               iommu_detected = 1;
+       }
+}
+
+static void __init init_no_remapping_devices(void)
+{
+       struct dmar_drhd_unit *drhd;
+
+       for_each_drhd_unit(drhd) {
+               if (!drhd->include_all) {
+                       int i;
+                       for (i = 0; i < drhd->devices_cnt; i++)
+                               if (drhd->devices[i] != NULL)
+                                       break;
+                       /* ignore DMAR unit if no pci devices exist */
+                       if (i == drhd->devices_cnt)
+                               drhd->ignored = 1;
+               }
+       }
+
+       if (dmar_map_gfx)
+               return;
+
+       for_each_drhd_unit(drhd) {
+               int i;
+               if (drhd->ignored || drhd->include_all)
+                       continue;
+
+               for (i = 0; i < drhd->devices_cnt; i++)
+                       if (drhd->devices[i] &&
+                               !IS_GFX_DEVICE(drhd->devices[i]))
+                               break;
+
+               if (i < drhd->devices_cnt)
+                       continue;
+
+               /* bypass IOMMU if it is just for gfx devices */
+               drhd->ignored = 1;
+               for (i = 0; i < drhd->devices_cnt; i++) {
+                       if (!drhd->devices[i])
+                               continue;
+                       drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
+               }
+       }
+}
+
+int __init intel_iommu_init(void)
+{
+       int ret = 0;
+
+       if (no_iommu || swiotlb || dmar_disabled)
+               return -ENODEV;
+
+       if (dmar_table_init())
+               return  -ENODEV;
+
+       iommu_init_mempool();
+       dmar_init_reserved_ranges();
+
+       init_no_remapping_devices();
+
+       ret = init_dmars();
+       if (ret) {
+               printk(KERN_ERR "IOMMU: dmar init failed\n");
+               put_iova_domain(&reserved_iova_list);
+               iommu_exit_mempool();
+               return ret;
+       }
+       printk(KERN_INFO
+       "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
+
+       force_iommu = 1;
+       dma_ops = &intel_dma_ops;
+       return 0;
+}
+
diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h
new file mode 100644 (file)
index 0000000..ee88dd2
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Ashok Raj <ashok.raj@intel.com>
+ * Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ */
+
+#ifndef _INTEL_IOMMU_H_
+#define _INTEL_IOMMU_H_
+
+#include <linux/types.h>
+#include <linux/msi.h>
+#include "iova.h"
+#include <linux/io.h>
+
+/*
+ * Intel IOMMU register specification per version 1.0 public spec.
+ */
+
+#define        DMAR_VER_REG    0x0     /* Arch version supported by this IOMMU */
+#define        DMAR_CAP_REG    0x8     /* Hardware supported capabilities */
+#define        DMAR_ECAP_REG   0x10    /* Extended capabilities supported */
+#define        DMAR_GCMD_REG   0x18    /* Global command register */
+#define        DMAR_GSTS_REG   0x1c    /* Global status register */
+#define        DMAR_RTADDR_REG 0x20    /* Root entry table */
+#define        DMAR_CCMD_REG   0x28    /* Context command reg */
+#define        DMAR_FSTS_REG   0x34    /* Fault Status register */
+#define        DMAR_FECTL_REG  0x38    /* Fault control register */
+#define        DMAR_FEDATA_REG 0x3c    /* Fault event interrupt data register */
+#define        DMAR_FEADDR_REG 0x40    /* Fault event interrupt addr register */
+#define        DMAR_FEUADDR_REG 0x44   /* Upper address register */
+#define        DMAR_AFLOG_REG  0x58    /* Advanced Fault control */
+#define        DMAR_PMEN_REG   0x64    /* Enable Protected Memory Region */
+#define        DMAR_PLMBASE_REG 0x68   /* PMRR Low addr */
+#define        DMAR_PLMLIMIT_REG 0x6c  /* PMRR low limit */
+#define        DMAR_PHMBASE_REG 0x70   /* pmrr high base addr */
+#define        DMAR_PHMLIMIT_REG 0x78  /* pmrr high limit */
+
+#define OFFSET_STRIDE          (9)
+/*
+#define dmar_readl(dmar, reg) readl(dmar + reg)
+#define dmar_readq(dmar, reg) ({ \
+               u32 lo, hi; \
+               lo = readl(dmar + reg); \
+               hi = readl(dmar + reg + 4); \
+               (((u64) hi) << 32) + lo; })
+*/
+static inline u64 dmar_readq(void *addr)
+{
+       u32 lo, hi;
+       lo = readl(addr);
+       hi = readl(addr + 4);
+       return (((u64) hi) << 32) + lo;
+}
+
+static inline void dmar_writeq(void __iomem *addr, u64 val)
+{
+       writel((u32)val, addr);
+       writel((u32)(val >> 32), addr + 4);
+}
+
+#define DMAR_VER_MAJOR(v)              (((v) & 0xf0) >> 4)
+#define DMAR_VER_MINOR(v)              ((v) & 0x0f)
+
+/*
+ * Decoding Capability Register
+ */
+#define cap_read_drain(c)      (((c) >> 55) & 1)
+#define cap_write_drain(c)     (((c) >> 54) & 1)
+#define cap_max_amask_val(c)   (((c) >> 48) & 0x3f)
+#define cap_num_fault_regs(c)  ((((c) >> 40) & 0xff) + 1)
+#define cap_pgsel_inv(c)       (((c) >> 39) & 1)
+
+#define cap_super_page_val(c)  (((c) >> 34) & 0xf)
+#define cap_super_offset(c)    (((find_first_bit(&cap_super_page_val(c), 4)) \
+                                       * OFFSET_STRIDE) + 21)
+
+#define cap_fault_reg_offset(c)        ((((c) >> 24) & 0x3ff) * 16)
+#define cap_max_fault_reg_offset(c) \
+       (cap_fault_reg_offset(c) + cap_num_fault_regs(c) * 16)
+
+#define cap_zlr(c)             (((c) >> 22) & 1)
+#define cap_isoch(c)           (((c) >> 23) & 1)
+#define cap_mgaw(c)            ((((c) >> 16) & 0x3f) + 1)
+#define cap_sagaw(c)           (((c) >> 8) & 0x1f)
+#define cap_caching_mode(c)    (((c) >> 7) & 1)
+#define cap_phmr(c)            (((c) >> 6) & 1)
+#define cap_plmr(c)            (((c) >> 5) & 1)
+#define cap_rwbf(c)            (((c) >> 4) & 1)
+#define cap_afl(c)             (((c) >> 3) & 1)
+#define cap_ndoms(c)           (((unsigned long)1) << (4 + 2 * ((c) & 0x7)))
+/*
+ * Extended Capability Register
+ */
+
+#define ecap_niotlb_iunits(e)  ((((e) >> 24) & 0xff) + 1)
+#define ecap_iotlb_offset(e)   ((((e) >> 8) & 0x3ff) * 16)
+#define ecap_max_iotlb_offset(e) \
+       (ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16)
+#define ecap_coherent(e)       ((e) & 0x1)
+
+
+/* IOTLB_REG */
+#define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60)
+#define DMA_TLB_DSI_FLUSH (((u64)2) << 60)
+#define DMA_TLB_PSI_FLUSH (((u64)3) << 60)
+#define DMA_TLB_IIRG(type) ((type >> 60) & 7)
+#define DMA_TLB_IAIG(val) (((val) >> 57) & 7)
+#define DMA_TLB_READ_DRAIN (((u64)1) << 49)
+#define DMA_TLB_WRITE_DRAIN (((u64)1) << 48)
+#define DMA_TLB_DID(id)        (((u64)((id) & 0xffff)) << 32)
+#define DMA_TLB_IVT (((u64)1) << 63)
+#define DMA_TLB_IH_NONLEAF (((u64)1) << 6)
+#define DMA_TLB_MAX_SIZE (0x3f)
+
+/* GCMD_REG */
+#define DMA_GCMD_TE (((u32)1) << 31)
+#define DMA_GCMD_SRTP (((u32)1) << 30)
+#define DMA_GCMD_SFL (((u32)1) << 29)
+#define DMA_GCMD_EAFL (((u32)1) << 28)
+#define DMA_GCMD_WBF (((u32)1) << 27)
+
+/* GSTS_REG */
+#define DMA_GSTS_TES (((u32)1) << 31)
+#define DMA_GSTS_RTPS (((u32)1) << 30)
+#define DMA_GSTS_FLS (((u32)1) << 29)
+#define DMA_GSTS_AFLS (((u32)1) << 28)
+#define DMA_GSTS_WBFS (((u32)1) << 27)
+
+/* CCMD_REG */
+#define DMA_CCMD_ICC (((u64)1) << 63)
+#define DMA_CCMD_GLOBAL_INVL (((u64)1) << 61)
+#define DMA_CCMD_DOMAIN_INVL (((u64)2) << 61)
+#define DMA_CCMD_DEVICE_INVL (((u64)3) << 61)
+#define DMA_CCMD_FM(m) (((u64)((m) & 0x3)) << 32)
+#define DMA_CCMD_MASK_NOBIT 0
+#define DMA_CCMD_MASK_1BIT 1
+#define DMA_CCMD_MASK_2BIT 2
+#define DMA_CCMD_MASK_3BIT 3
+#define DMA_CCMD_SID(s) (((u64)((s) & 0xffff)) << 16)
+#define DMA_CCMD_DID(d) ((u64)((d) & 0xffff))
+
+/* FECTL_REG */
+#define DMA_FECTL_IM (((u32)1) << 31)
+
+/* FSTS_REG */
+#define DMA_FSTS_PPF ((u32)2)
+#define DMA_FSTS_PFO ((u32)1)
+#define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff)
+
+/* FRCD_REG, 32 bits access */
+#define DMA_FRCD_F (((u32)1) << 31)
+#define dma_frcd_type(d) ((d >> 30) & 1)
+#define dma_frcd_fault_reason(c) (c & 0xff)
+#define dma_frcd_source_id(c) (c & 0xffff)
+#define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */
+
+/*
+ * 0: Present
+ * 1-11: Reserved
+ * 12-63: Context Ptr (12 - (haw-1))
+ * 64-127: Reserved
+ */
+struct root_entry {
+       u64     val;
+       u64     rsvd1;
+};
+#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry))
+static inline bool root_present(struct root_entry *root)
+{
+       return (root->val & 1);
+}
+static inline void set_root_present(struct root_entry *root)
+{
+       root->val |= 1;
+}
+static inline void set_root_value(struct root_entry *root, unsigned long value)
+{
+       root->val |= value & PAGE_MASK_4K;
+}
+
+struct context_entry;
+static inline struct context_entry *
+get_context_addr_from_root(struct root_entry *root)
+{
+       return (struct context_entry *)
+               (root_present(root)?phys_to_virt(
+               root->val & PAGE_MASK_4K):
+               NULL);
+}
+
+/*
+ * low 64 bits:
+ * 0: present
+ * 1: fault processing disable
+ * 2-3: translation type
+ * 12-63: address space root
+ * high 64 bits:
+ * 0-2: address width
+ * 3-6: aval
+ * 8-23: domain id
+ */
+struct context_entry {
+       u64 lo;
+       u64 hi;
+};
+#define context_present(c) ((c).lo & 1)
+#define context_fault_disable(c) (((c).lo >> 1) & 1)
+#define context_translation_type(c) (((c).lo >> 2) & 3)
+#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
+#define context_address_width(c) ((c).hi &  7)
+#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
+
+#define context_set_present(c) do {(c).lo |= 1;} while (0)
+#define context_set_fault_enable(c) \
+       do {(c).lo &= (((u64)-1) << 2) | 1;} while (0)
+#define context_set_translation_type(c, val) \
+       do { \
+               (c).lo &= (((u64)-1) << 4) | 3; \
+               (c).lo |= ((val) & 3) << 2; \
+       } while (0)
+#define CONTEXT_TT_MULTI_LEVEL 0
+#define context_set_address_root(c, val) \
+       do {(c).lo |= (val) & PAGE_MASK_4K;} while (0)
+#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
+#define context_set_domain_id(c, val) \
+       do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
+#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0)
+
+/*
+ * 0: readable
+ * 1: writable
+ * 2-6: reserved
+ * 7: super page
+ * 8-11: available
+ * 12-63: Host physcial address
+ */
+struct dma_pte {
+       u64 val;
+};
+#define dma_clear_pte(p)       do {(p).val = 0;} while (0)
+
+#define DMA_PTE_READ (1)
+#define DMA_PTE_WRITE (2)
+
+#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0)
+#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
+#define dma_set_pte_prot(p, prot) \
+               do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
+#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
+#define dma_set_pte_addr(p, addr) do {\
+               (p).val |= ((addr) & PAGE_MASK_4K); } while (0)
+#define dma_pte_present(p) (((p).val & 3) != 0)
+
+struct intel_iommu;
+
+struct dmar_domain {
+       int     id;                     /* domain id */
+       struct intel_iommu *iommu;      /* back pointer to owning iommu */
+
+       struct list_head devices;       /* all devices' list */
+       struct iova_domain iovad;       /* iova's that belong to this domain */
+
+       struct dma_pte  *pgd;           /* virtual address */
+       spinlock_t      mapping_lock;   /* page table lock */
+       int             gaw;            /* max guest address width */
+
+       /* adjusted guest address width, 0 is level 2 30-bit */
+       int             agaw;
+
+#define DOMAIN_FLAG_MULTIPLE_DEVICES 1
+       int             flags;
+};
+
+/* PCI domain-device relationship */
+struct device_domain_info {
+       struct list_head link;  /* link to domain siblings */
+       struct list_head global; /* link to global list */
+       u8 bus;                 /* PCI bus numer */
+       u8 devfn;               /* PCI devfn number */
+       struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
+       struct dmar_domain *domain; /* pointer to domain */
+};
+
+extern int init_dmars(void);
+
+struct intel_iommu {
+       void __iomem    *reg; /* Pointer to hardware regs, virtual addr */
+       u64             cap;
+       u64             ecap;
+       unsigned long   *domain_ids; /* bitmap of domains */
+       struct dmar_domain **domains; /* ptr to domains */
+       int             seg;
+       u32             gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
+       spinlock_t      lock; /* protect context, domain ids */
+       spinlock_t      register_lock; /* protect register handling */
+       struct root_entry *root_entry; /* virtual address */
+
+       unsigned int irq;
+       unsigned char name[7];    /* Device Name */
+       struct msi_msg saved_msg;
+       struct sys_device sysdev;
+};
+
+#ifndef CONFIG_DMAR_GFX_WA
+static inline void iommu_prepare_gfx_mapping(void)
+{
+       return;
+}
+#endif /* !CONFIG_DMAR_GFX_WA */
+
+#endif
diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c
new file mode 100644 (file)
index 0000000..a84571c
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This file is released under the GPLv2.
+ *
+ * Copyright (C) 2006 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ */
+
+#include "iova.h"
+
+void
+init_iova_domain(struct iova_domain *iovad)
+{
+       spin_lock_init(&iovad->iova_alloc_lock);
+       spin_lock_init(&iovad->iova_rbtree_lock);
+       iovad->rbroot = RB_ROOT;
+       iovad->cached32_node = NULL;
+
+}
+
+static struct rb_node *
+__get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
+{
+       if ((*limit_pfn != DMA_32BIT_PFN) ||
+               (iovad->cached32_node == NULL))
+               return rb_last(&iovad->rbroot);
+       else {
+               struct rb_node *prev_node = rb_prev(iovad->cached32_node);
+               struct iova *curr_iova =
+                       container_of(iovad->cached32_node, struct iova, node);
+               *limit_pfn = curr_iova->pfn_lo - 1;
+               return prev_node;
+       }
+}
+
+static void
+__cached_rbnode_insert_update(struct iova_domain *iovad,
+       unsigned long limit_pfn, struct iova *new)
+{
+       if (limit_pfn != DMA_32BIT_PFN)
+               return;
+       iovad->cached32_node = &new->node;
+}
+
+static void
+__cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free)
+{
+       struct iova *cached_iova;
+       struct rb_node *curr;
+
+       if (!iovad->cached32_node)
+               return;
+       curr = iovad->cached32_node;
+       cached_iova = container_of(curr, struct iova, node);
+
+       if (free->pfn_lo >= cached_iova->pfn_lo)
+               iovad->cached32_node = rb_next(&free->node);
+}
+
+/* Computes the padding size required, to make the
+ * the start address naturally aligned on its size
+ */
+static int
+iova_get_pad_size(int size, unsigned int limit_pfn)
+{
+       unsigned int pad_size = 0;
+       unsigned int order = ilog2(size);
+
+       if (order)
+               pad_size = (limit_pfn + 1) % (1 << order);
+
+       return pad_size;
+}
+
+static int __alloc_iova_range(struct iova_domain *iovad, unsigned long size,
+               unsigned long limit_pfn, struct iova *new, bool size_aligned)
+{
+       struct rb_node *curr = NULL;
+       unsigned long flags;
+       unsigned long saved_pfn;
+       unsigned int pad_size = 0;
+
+       /* Walk the tree backwards */
+       spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
+       saved_pfn = limit_pfn;
+       curr = __get_cached_rbnode(iovad, &limit_pfn);
+       while (curr) {
+               struct iova *curr_iova = container_of(curr, struct iova, node);
+               if (limit_pfn < curr_iova->pfn_lo)
+                       goto move_left;
+               else if (limit_pfn < curr_iova->pfn_hi)
+                       goto adjust_limit_pfn;
+               else {
+                       if (size_aligned)
+                               pad_size = iova_get_pad_size(size, limit_pfn);
+                       if ((curr_iova->pfn_hi + size + pad_size) <= limit_pfn)
+                               break;  /* found a free slot */
+               }
+adjust_limit_pfn:
+               limit_pfn = curr_iova->pfn_lo - 1;
+move_left:
+               curr = rb_prev(curr);
+       }
+
+       if (!curr) {
+               if (size_aligned)
+                       pad_size = iova_get_pad_size(size, limit_pfn);
+               if ((IOVA_START_PFN + size + pad_size) > limit_pfn) {
+                       spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+                       return -ENOMEM;
+               }
+       }
+
+       /* pfn_lo will point to size aligned address if size_aligned is set */
+       new->pfn_lo = limit_pfn - (size + pad_size) + 1;
+       new->pfn_hi = new->pfn_lo + size - 1;
+
+       spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+       return 0;
+}
+
+static void
+iova_insert_rbtree(struct rb_root *root, struct iova *iova)
+{
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       /* Figure out where to put new node */
+       while (*new) {
+               struct iova *this = container_of(*new, struct iova, node);
+               parent = *new;
+
+               if (iova->pfn_lo < this->pfn_lo)
+                       new = &((*new)->rb_left);
+               else if (iova->pfn_lo > this->pfn_lo)
+                       new = &((*new)->rb_right);
+               else
+                       BUG(); /* this should not happen */
+       }
+       /* Add new node and rebalance tree. */
+       rb_link_node(&iova->node, parent, new);
+       rb_insert_color(&iova->node, root);
+}
+
+/**
+ * alloc_iova - allocates an iova
+ * @iovad - iova domain in question
+ * @size - size of page frames to allocate
+ * @limit_pfn - max limit address
+ * @size_aligned - set if size_aligned address range is required
+ * This function allocates an iova in the range limit_pfn to IOVA_START_PFN
+ * looking from limit_pfn instead from IOVA_START_PFN. If the size_aligned
+ * flag is set then the allocated address iova->pfn_lo will be naturally
+ * aligned on roundup_power_of_two(size).
+ */
+struct iova *
+alloc_iova(struct iova_domain *iovad, unsigned long size,
+       unsigned long limit_pfn,
+       bool size_aligned)
+{
+       unsigned long flags;
+       struct iova *new_iova;
+       int ret;
+
+       new_iova = alloc_iova_mem();
+       if (!new_iova)
+               return NULL;
+
+       /* If size aligned is set then round the size to
+        * to next power of two.
+        */
+       if (size_aligned)
+               size = __roundup_pow_of_two(size);
+
+       spin_lock_irqsave(&iovad->iova_alloc_lock, flags);
+       ret = __alloc_iova_range(iovad, size, limit_pfn, new_iova,
+                       size_aligned);
+
+       if (ret) {
+               spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
+               free_iova_mem(new_iova);
+               return NULL;
+       }
+
+       /* Insert the new_iova into domain rbtree by holding writer lock */
+       spin_lock(&iovad->iova_rbtree_lock);
+       iova_insert_rbtree(&iovad->rbroot, new_iova);
+       __cached_rbnode_insert_update(iovad, limit_pfn, new_iova);
+       spin_unlock(&iovad->iova_rbtree_lock);
+
+       spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
+
+       return new_iova;
+}
+
+/**
+ * find_iova - find's an iova for a given pfn
+ * @iovad - iova domain in question.
+ * pfn - page frame number
+ * This function finds and returns an iova belonging to the
+ * given doamin which matches the given pfn.
+ */
+struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn)
+{
+       unsigned long flags;
+       struct rb_node *node;
+
+       /* Take the lock so that no other thread is manipulating the rbtree */
+       spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
+       node = iovad->rbroot.rb_node;
+       while (node) {
+               struct iova *iova = container_of(node, struct iova, node);
+
+               /* If pfn falls within iova's range, return iova */
+               if ((pfn >= iova->pfn_lo) && (pfn <= iova->pfn_hi)) {
+                       spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+                       /* We are not holding the lock while this iova
+                        * is referenced by the caller as the same thread
+                        * which called this function also calls __free_iova()
+                        * and it is by desing that only one thread can possibly
+                        * reference a particular iova and hence no conflict.
+                        */
+                       return iova;
+               }
+
+               if (pfn < iova->pfn_lo)
+                       node = node->rb_left;
+               else if (pfn > iova->pfn_lo)
+                       node = node->rb_right;
+       }
+
+       spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+       return NULL;
+}
+
+/**
+ * __free_iova - frees the given iova
+ * @iovad: iova domain in question.
+ * @iova: iova in question.
+ * Frees the given iova belonging to the giving domain
+ */
+void
+__free_iova(struct iova_domain *iovad, struct iova *iova)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
+       __cached_rbnode_delete_update(iovad, iova);
+       rb_erase(&iova->node, &iovad->rbroot);
+       spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+       free_iova_mem(iova);
+}
+
+/**
+ * free_iova - finds and frees the iova for a given pfn
+ * @iovad: - iova domain in question.
+ * @pfn: - pfn that is allocated previously
+ * This functions finds an iova for a given pfn and then
+ * frees the iova from that domain.
+ */
+void
+free_iova(struct iova_domain *iovad, unsigned long pfn)
+{
+       struct iova *iova = find_iova(iovad, pfn);
+       if (iova)
+               __free_iova(iovad, iova);
+
+}
+
+/**
+ * put_iova_domain - destroys the iova doamin
+ * @iovad: - iova domain in question.
+ * All the iova's in that domain are destroyed.
+ */
+void put_iova_domain(struct iova_domain *iovad)
+{
+       struct rb_node *node;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
+       node = rb_first(&iovad->rbroot);
+       while (node) {
+               struct iova *iova = container_of(node, struct iova, node);
+               rb_erase(node, &iovad->rbroot);
+               free_iova_mem(iova);
+               node = rb_first(&iovad->rbroot);
+       }
+       spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+}
+
+static int
+__is_range_overlap(struct rb_node *node,
+       unsigned long pfn_lo, unsigned long pfn_hi)
+{
+       struct iova *iova = container_of(node, struct iova, node);
+
+       if ((pfn_lo <= iova->pfn_hi) && (pfn_hi >= iova->pfn_lo))
+               return 1;
+       return 0;
+}
+
+static struct iova *
+__insert_new_range(struct iova_domain *iovad,
+       unsigned long pfn_lo, unsigned long pfn_hi)
+{
+       struct iova *iova;
+
+       iova = alloc_iova_mem();
+       if (!iova)
+               return iova;
+
+       iova->pfn_hi = pfn_hi;
+       iova->pfn_lo = pfn_lo;
+       iova_insert_rbtree(&iovad->rbroot, iova);
+       return iova;
+}
+
+static void
+__adjust_overlap_range(struct iova *iova,
+       unsigned long *pfn_lo, unsigned long *pfn_hi)
+{
+       if (*pfn_lo < iova->pfn_lo)
+               iova->pfn_lo = *pfn_lo;
+       if (*pfn_hi > iova->pfn_hi)
+               *pfn_lo = iova->pfn_hi + 1;
+}
+
+/**
+ * reserve_iova - reserves an iova in the given range
+ * @iovad: - iova domain pointer
+ * @pfn_lo: - lower page frame address
+ * @pfn_hi:- higher pfn adderss
+ * This function allocates reserves the address range from pfn_lo to pfn_hi so
+ * that this address is not dished out as part of alloc_iova.
+ */
+struct iova *
+reserve_iova(struct iova_domain *iovad,
+       unsigned long pfn_lo, unsigned long pfn_hi)
+{
+       struct rb_node *node;
+       unsigned long flags;
+       struct iova *iova;
+       unsigned int overlap = 0;
+
+       spin_lock_irqsave(&iovad->iova_alloc_lock, flags);
+       spin_lock(&iovad->iova_rbtree_lock);
+       for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) {
+               if (__is_range_overlap(node, pfn_lo, pfn_hi)) {
+                       iova = container_of(node, struct iova, node);
+                       __adjust_overlap_range(iova, &pfn_lo, &pfn_hi);
+                       if ((pfn_lo >= iova->pfn_lo) &&
+                               (pfn_hi <= iova->pfn_hi))
+                               goto finish;
+                       overlap = 1;
+
+               } else if (overlap)
+                               break;
+       }
+
+       /* We are here either becasue this is the first reserver node
+        * or need to insert remaining non overlap addr range
+        */
+       iova = __insert_new_range(iovad, pfn_lo, pfn_hi);
+finish:
+
+       spin_unlock(&iovad->iova_rbtree_lock);
+       spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
+       return iova;
+}
+
+/**
+ * copy_reserved_iova - copies the reserved between domains
+ * @from: - source doamin from where to copy
+ * @to: - destination domin where to copy
+ * This function copies reserved iova's from one doamin to
+ * other.
+ */
+void
+copy_reserved_iova(struct iova_domain *from, struct iova_domain *to)
+{
+       unsigned long flags;
+       struct rb_node *node;
+
+       spin_lock_irqsave(&from->iova_alloc_lock, flags);
+       spin_lock(&from->iova_rbtree_lock);
+       for (node = rb_first(&from->rbroot); node; node = rb_next(node)) {
+               struct iova *iova = container_of(node, struct iova, node);
+               struct iova *new_iova;
+               new_iova = reserve_iova(to, iova->pfn_lo, iova->pfn_hi);
+               if (!new_iova)
+                       printk(KERN_ERR "Reserve iova range %lx@%lx failed\n",
+                               iova->pfn_lo, iova->pfn_lo);
+       }
+       spin_unlock(&from->iova_rbtree_lock);
+       spin_unlock_irqrestore(&from->iova_alloc_lock, flags);
+}
diff --git a/drivers/pci/iova.h b/drivers/pci/iova.h
new file mode 100644 (file)
index 0000000..ae3028d
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This file is released under the GPLv2.
+ *
+ * Copyright (C) 2006 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ *
+ */
+
+#ifndef _IOVA_H_
+#define _IOVA_H_
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/rbtree.h>
+#include <linux/dma-mapping.h>
+
+/*
+ * We need a fixed PAGE_SIZE of 4K irrespective of
+ * arch PAGE_SIZE for IOMMU page tables.
+ */
+#define PAGE_SHIFT_4K          (12)
+#define PAGE_SIZE_4K           (1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K           (((u64)-1) << PAGE_SHIFT_4K)
+#define PAGE_ALIGN_4K(addr)    (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
+
+/* IO virtual address start page frame number */
+#define IOVA_START_PFN         (1)
+
+#define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT_4K)
+#define DMA_32BIT_PFN  IOVA_PFN(DMA_32BIT_MASK)
+#define DMA_64BIT_PFN  IOVA_PFN(DMA_64BIT_MASK)
+
+/* iova structure */
+struct iova {
+       struct rb_node  node;
+       unsigned long   pfn_hi; /* IOMMU dish out addr hi */
+       unsigned long   pfn_lo; /* IOMMU dish out addr lo */
+};
+
+/* holds all the iova translations for a domain */
+struct iova_domain {
+       spinlock_t      iova_alloc_lock;/* Lock to protect iova  allocation */
+       spinlock_t      iova_rbtree_lock; /* Lock to protect update of rbtree */
+       struct rb_root  rbroot;         /* iova domain rbtree root */
+       struct rb_node  *cached32_node; /* Save last alloced node */
+};
+
+struct iova *alloc_iova_mem(void);
+void free_iova_mem(struct iova *iova);
+void free_iova(struct iova_domain *iovad, unsigned long pfn);
+void __free_iova(struct iova_domain *iovad, struct iova *iova);
+struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size,
+       unsigned long limit_pfn,
+       bool size_aligned);
+struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
+       unsigned long pfn_hi);
+void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
+void init_iova_domain(struct iova_domain *iovad);
+struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
+void put_iova_domain(struct iova_domain *iovad);
+
+#endif
index 6fda33d..fc87e14 100644 (file)
@@ -90,3 +90,4 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
        return NULL;
 }
 
+struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev);
index 5db6b66..463a5a9 100644 (file)
@@ -837,6 +837,19 @@ static void pci_release_dev(struct device *dev)
        kfree(pci_dev);
 }
 
+static void set_pcie_port_type(struct pci_dev *pdev)
+{
+       int pos;
+       u16 reg16;
+
+       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       if (!pos)
+               return;
+       pdev->is_pcie = 1;
+       pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
+       pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
 /**
  * pci_cfg_space_size - get the configuration space size of the PCI device.
  * @dev: PCI device
@@ -951,6 +964,7 @@ pci_scan_device(struct pci_bus *bus, int devfn)
        dev->device = (l >> 16) & 0xffff;
        dev->cfg_size = pci_cfg_space_size(dev);
        dev->error_state = pci_channel_io_normal;
+       set_pcie_port_type(dev);
 
        /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
           set this higher, assuming the system even supports it.  */
index c6e79d0..b001b59 100644 (file)
 #include "pci.h"
 
 DECLARE_RWSEM(pci_bus_sem);
+/*
+ * find the upstream PCIE-to-PCI bridge of a PCI device
+ * if the device is PCIE, return NULL
+ * if the device isn't connected to a PCIE bridge (that is its parent is a
+ * legacy PCI bridge and the bridge is directly connected to bus 0), return its
+ * parent
+ */
+struct pci_dev *
+pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
+{
+       struct pci_dev *tmp = NULL;
+
+       if (pdev->is_pcie)
+               return NULL;
+       while (1) {
+               if (!pdev->bus->self)
+                       break;
+               pdev = pdev->bus->self;
+               /* a p2p bridge */
+               if (!pdev->is_pcie) {
+                       tmp = pdev;
+                       continue;
+               }
+               /* PCI device should connect to a PCIE bridge */
+               if (pdev->pcie_type != PCI_EXP_TYPE_PCI_BRIDGE) {
+                       /* Busted hardware? */
+                       WARN_ON_ONCE(1);
+                       return NULL;
+               }
+               return pdev;
+       }
+
+       return tmp;
+}
 
 static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
 {
index 39a90a6..bbf3ee1 100644 (file)
@@ -26,65 +26,124 @@ static struct power_supply *main_battery;
 static void find_main_battery(void)
 {
        struct device *dev;
-       struct power_supply *bat, *batm;
+       struct power_supply *bat = NULL;
+       struct power_supply *max_charge_bat = NULL;
+       struct power_supply *max_energy_bat = NULL;
        union power_supply_propval full;
        int max_charge = 0;
+       int max_energy = 0;
 
        main_battery = NULL;
-       batm = NULL;
+
        list_for_each_entry(dev, &power_supply_class->devices, node) {
                bat = dev_get_drvdata(dev);
-               /* If none of battery devices cantains 'use_for_apm' flag,
-                  choice one with maximum design charge */
-               if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) {
+
+               if (bat->use_for_apm) {
+                       /* nice, we explicitly asked to report this battery. */
+                       main_battery = bat;
+                       return;
+               }
+
+               if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) ||
+                               !PSY_PROP(bat, CHARGE_FULL, &full)) {
                        if (full.intval > max_charge) {
-                               batm = bat;
+                               max_charge_bat = bat;
                                max_charge = full.intval;
                        }
+               } else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) ||
+                               !PSY_PROP(bat, ENERGY_FULL, &full)) {
+                       if (full.intval > max_energy) {
+                               max_energy_bat = bat;
+                               max_energy = full.intval;
+                       }
                }
+       }
 
-               if (bat->use_for_apm)
-                       main_battery = bat;
+       if ((max_energy_bat && max_charge_bat) &&
+                       (max_energy_bat != max_charge_bat)) {
+               /* try guess battery with more capacity */
+               if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) {
+                       if (max_energy > max_charge * full.intval)
+                               main_battery = max_energy_bat;
+                       else
+                               main_battery = max_charge_bat;
+               } else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN,
+                                                                 &full)) {
+                       if (max_charge > max_energy / full.intval)
+                               main_battery = max_charge_bat;
+                       else
+                               main_battery = max_energy_bat;
+               } else {
+                       /* give up, choice any */
+                       main_battery = max_energy_bat;
+               }
+       } else if (max_charge_bat) {
+               main_battery = max_charge_bat;
+       } else if (max_energy_bat) {
+               main_battery = max_energy_bat;
+       } else {
+               /* give up, try the last if any */
+               main_battery = bat;
        }
-       if (!main_battery)
-               main_battery = batm;
 }
 
-static int calculate_time(int status)
+static int calculate_time(int status, int using_charge)
 {
-       union power_supply_propval charge_full, charge_empty;
-       union power_supply_propval charge, I;
+       union power_supply_propval full;
+       union power_supply_propval empty;
+       union power_supply_propval cur;
+       union power_supply_propval I;
+       enum power_supply_property full_prop;
+       enum power_supply_property full_design_prop;
+       enum power_supply_property empty_prop;
+       enum power_supply_property empty_design_prop;
+       enum power_supply_property cur_avg_prop;
+       enum power_supply_property cur_now_prop;
 
-       if (MPSY_PROP(CHARGE_FULL, &charge_full)) {
-               /* if battery can't report this property, use design value */
-               if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full))
+       if (MPSY_PROP(CURRENT_AVG, &I)) {
+               /* if battery can't report average value, use momentary */
+               if (MPSY_PROP(CURRENT_NOW, &I))
                        return -1;
        }
 
-       if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) {
-               /* if battery can't report this property, use design value */
-               if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty))
-                       charge_empty.intval = 0;
+       if (using_charge) {
+               full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
+               full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
+               empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+               empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+               cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
+               cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
+       } else {
+               full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
+               full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
+               empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
+               empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+               cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
+               cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
        }
 
-       if (MPSY_PROP(CHARGE_AVG, &charge)) {
-               /* if battery can't report average value, use momentary */
-               if (MPSY_PROP(CHARGE_NOW, &charge))
+       if (_MPSY_PROP(full_prop, &full)) {
+               /* if battery can't report this property, use design value */
+               if (_MPSY_PROP(full_design_prop, &full))
                        return -1;
        }
 
-       if (MPSY_PROP(CURRENT_AVG, &I)) {
+       if (_MPSY_PROP(empty_prop, &empty)) {
+               /* if battery can't report this property, use design value */
+               if (_MPSY_PROP(empty_design_prop, &empty))
+                       empty.intval = 0;
+       }
+
+       if (_MPSY_PROP(cur_avg_prop, &cur)) {
                /* if battery can't report average value, use momentary */
-               if (MPSY_PROP(CURRENT_NOW, &I))
+               if (_MPSY_PROP(cur_now_prop, &cur))
                        return -1;
        }
 
        if (status == POWER_SUPPLY_STATUS_CHARGING)
-               return ((charge.intval - charge_full.intval) * 60L) /
-                      I.intval;
+               return ((cur.intval - full.intval) * 60L) / I.intval;
        else
-               return -((charge.intval - charge_empty.intval) * 60L) /
-                       I.intval;
+               return -((cur.intval - empty.intval) * 60L) / I.intval;
 }
 
 static int calculate_capacity(int using_charge)
@@ -200,18 +259,22 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
        info->units = APM_UNITS_MINS;
 
        if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
-               if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) {
-                       if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
-                               info->time = calculate_time(status.intval);
-                       else
-                               info->time = time_to_full.intval / 60;
+               if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
+                               !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {
+                       info->time = time_to_full.intval / 60;
+               } else {
+                       info->time = calculate_time(status.intval, 0);
+                       if (info->time == -1)
+                               info->time = calculate_time(status.intval, 1);
                }
        } else {
-               if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) {
-                       if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
-                               info->time = calculate_time(status.intval);
-                       else
-                               info->time = time_to_empty.intval / 60;
+               if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
+                             !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {
+                       info->time = time_to_empty.intval / 60;
+               } else {
+                       info->time = calculate_time(status.intval, 0);
+                       if (info->time == -1)
+                               info->time = calculate_time(status.intval, 1);
                }
        }
 
index 2edd5fb..8d1c64a 100644 (file)
@@ -48,8 +48,8 @@ struct raw3270 {
        struct timer_list timer;        /* Device timer. */
 
        unsigned char *ascebc;          /* ascii -> ebcdic table */
-       struct class_device *clttydev;  /* 3270-class tty device ptr */
-       struct class_device *cltubdev;  /* 3270-class tub device ptr */
+       struct device *clttydev;        /* 3270-class tty device ptr */
+       struct device *cltubdev;        /* 3270-class tub device ptr */
 
        struct raw3270_request init_request;
        unsigned char init_data[256];
@@ -1107,11 +1107,9 @@ raw3270_delete_device(struct raw3270 *rp)
        /* Remove from device chain. */
        mutex_lock(&raw3270_mutex);
        if (rp->clttydev && !IS_ERR(rp->clttydev))
-               class_device_destroy(class3270,
-                                    MKDEV(IBM_TTY3270_MAJOR, rp->minor));
+               device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
        if (rp->cltubdev && !IS_ERR(rp->cltubdev))
-               class_device_destroy(class3270,
-                                    MKDEV(IBM_FS3270_MAJOR, rp->minor));
+               device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, rp->minor));
        list_del_init(&rp->list);
        mutex_unlock(&raw3270_mutex);
 
@@ -1181,24 +1179,22 @@ static int raw3270_create_attributes(struct raw3270 *rp)
        if (rc)
                goto out;
 
-       rp->clttydev = class_device_create(class3270, NULL,
-                                          MKDEV(IBM_TTY3270_MAJOR, rp->minor),
-                                          &rp->cdev->dev, "tty%s",
-                                          rp->cdev->dev.bus_id);
+       rp->clttydev = device_create(class3270, &rp->cdev->dev,
+                                    MKDEV(IBM_TTY3270_MAJOR, rp->minor),
+                                    "tty%s", rp->cdev->dev.bus_id);
        if (IS_ERR(rp->clttydev)) {
                rc = PTR_ERR(rp->clttydev);
                goto out_ttydev;
        }
 
-       rp->cltubdev = class_device_create(class3270, NULL,
-                                          MKDEV(IBM_FS3270_MAJOR, rp->minor),
-                                          &rp->cdev->dev, "tub%s",
-                                          rp->cdev->dev.bus_id);
+       rp->cltubdev = device_create(class3270, &rp->cdev->dev,
+                                    MKDEV(IBM_FS3270_MAJOR, rp->minor),
+                                    "tub%s", rp->cdev->dev.bus_id);
        if (!IS_ERR(rp->cltubdev))
                goto out;
 
        rc = PTR_ERR(rp->cltubdev);
-       class_device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
+       device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
 
 out_ttydev:
        sysfs_remove_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
index 2e0d297..aa7f166 100644 (file)
@@ -69,12 +69,9 @@ struct tape_class_device *register_tape_dev(
        if (rc)
                goto fail_with_cdev;
 
-       tcd->class_device = class_device_create(
-                               tape_class,
-                               NULL,
-                               tcd->char_device->dev,
-                               device,
-                               "%s", tcd->device_name
+       tcd->class_device = device_create(tape_class, device,
+                                         tcd->char_device->dev,
+                                         "%s", tcd->device_name
                        );
        rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0;
        if (rc)
@@ -90,7 +87,7 @@ struct tape_class_device *register_tape_dev(
        return tcd;
 
 fail_with_class_device:
-       class_device_destroy(tape_class, tcd->char_device->dev);
+       device_destroy(tape_class, tcd->char_device->dev);
 
 fail_with_cdev:
        cdev_del(tcd->char_device);
@@ -105,11 +102,9 @@ EXPORT_SYMBOL(register_tape_dev);
 void unregister_tape_dev(struct tape_class_device *tcd)
 {
        if (tcd != NULL && !IS_ERR(tcd)) {
-               sysfs_remove_link(
-                       &tcd->class_device->dev->kobj,
-                       tcd->mode_name
-               );
-               class_device_destroy(tape_class, tcd->char_device->dev);
+               sysfs_remove_link(&tcd->class_device->kobj,
+                                 tcd->mode_name);
+               device_destroy(tape_class, tcd->char_device->dev);
                cdev_del(tcd->char_device);
                kfree(tcd);
        }
index a8bd9b4..e2b5ac9 100644 (file)
@@ -24,8 +24,8 @@
 #define TAPECLASS_NAME_LEN     32
 
 struct tape_class_device {
-       struct cdev *           char_device;
-       struct class_device *   class_device;
+       struct cdev             *char_device;
+       struct device           *class_device;
        char                    device_name[TAPECLASS_NAME_LEN];
        char                    mode_name[TAPECLASS_NAME_LEN];
 };
index 12f7a4c..e0c4c50 100644 (file)
@@ -74,7 +74,7 @@ struct vmlogrdr_priv_t {
        int dev_in_use; /* 1: already opened, 0: not opened*/
        spinlock_t priv_lock;
        struct device  *device;
-       struct class_device  *class_device;
+       struct device  *class_device;
        int autorecording;
        int autopurge;
 };
@@ -762,12 +762,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
                device_unregister(dev);
                return ret;
        }
-       priv->class_device = class_device_create(
-                               vmlogrdr_class,
-                               NULL,
-                               MKDEV(vmlogrdr_major, priv->minor_num),
-                               dev,
-                               "%s", dev->bus_id );
+       priv->class_device = device_create(vmlogrdr_class, dev,
+                                          MKDEV(vmlogrdr_major,
+                                                priv->minor_num),
+                                          "%s", dev->bus_id);
        if (IS_ERR(priv->class_device)) {
                ret = PTR_ERR(priv->class_device);
                priv->class_device=NULL;
@@ -783,8 +781,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
 
 static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv)
 {
-       class_device_destroy(vmlogrdr_class,
-                            MKDEV(vmlogrdr_major, priv->minor_num));
+       device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
        if (priv->device != NULL) {
                sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
                device_unregister(priv->device);
index 42c1f46..297cdce 100644 (file)
@@ -246,7 +246,7 @@ int chp_add_cmg_attr(struct channel_path *chp)
 static ssize_t chp_status_show(struct device *dev,
                               struct device_attribute *attr, char *buf)
 {
-       struct channel_path *chp = container_of(dev, struct channel_path, dev);
+       struct channel_path *chp = to_channelpath(dev);
 
        if (!chp)
                return 0;
@@ -258,7 +258,7 @@ static ssize_t chp_status_write(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
-       struct channel_path *cp = container_of(dev, struct channel_path, dev);
+       struct channel_path *cp = to_channelpath(dev);
        char cmd[10];
        int num_args;
        int error;
@@ -286,7 +286,7 @@ static ssize_t chp_configure_show(struct device *dev,
        struct channel_path *cp;
        int status;
 
-       cp = container_of(dev, struct channel_path, dev);
+       cp = to_channelpath(dev);
        status = chp_info_get_status(cp->chpid);
        if (status < 0)
                return status;
@@ -308,7 +308,7 @@ static ssize_t chp_configure_write(struct device *dev,
                return -EINVAL;
        if (val != 0 && val != 1)
                return -EINVAL;
-       cp = container_of(dev, struct channel_path, dev);
+       cp = to_channelpath(dev);
        chp_cfg_schedule(cp->chpid, val);
        cfg_wait_idle();
 
@@ -320,7 +320,7 @@ static DEVICE_ATTR(configure, 0644, chp_configure_show, chp_configure_write);
 static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
-       struct channel_path *chp = container_of(dev, struct channel_path, dev);
+       struct channel_path *chp = to_channelpath(dev);
 
        if (!chp)
                return 0;
@@ -374,7 +374,7 @@ static void chp_release(struct device *dev)
 {
        struct channel_path *cp;
 
-       cp = container_of(dev, struct channel_path, dev);
+       cp = to_channelpath(dev);
        kfree(cp);
 }
 
index 5d83dd4..838f7ac 100644 (file)
@@ -182,6 +182,15 @@ static int css_register_subchannel(struct subchannel *sch)
        sch->dev.bus = &css_bus_type;
        sch->dev.release = &css_subchannel_release;
        sch->dev.groups = subch_attr_groups;
+       /*
+        * We don't want to generate uevents for I/O subchannels that don't
+        * have a working ccw device behind them since they will be
+        * unregistered before they can be used anyway, so we delay the add
+        * uevent until after device recognition was successful.
+        */
+       if (!cio_is_console(sch->schid))
+               /* Console is special, no need to suppress. */
+               sch->dev.uevent_suppress = 1;
        css_update_ssd_info(sch);
        /* make it known to the system */
        ret = css_sch_device_register(sch);
index 7507067..fd5d0c1 100644 (file)
@@ -559,6 +559,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
                retval = -ENOMEM;
                goto out;
        }
+       sg_init_table(sg_list->sg, sg_list->count);
 
        for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) {
                sg->length = min(size, PAGE_SIZE);
index 57cac70..326e7ee 100644 (file)
@@ -63,7 +63,7 @@
 static inline void *
 zfcp_sg_to_address(struct scatterlist *list)
 {
-       return (void *) (page_address(list->page) + list->offset);
+       return sg_virt(list);
 }
 
 /**
@@ -74,7 +74,7 @@ zfcp_sg_to_address(struct scatterlist *list)
 static inline void
 zfcp_address_to_sg(void *address, struct scatterlist *list)
 {
-       list->page = virt_to_page(address);
+       sg_set_page(list, virt_to_page(address));
        list->offset = ((unsigned long) address) & (PAGE_SIZE - 1);
 }
 
index a6475a2..9438d0b 100644 (file)
@@ -308,13 +308,15 @@ zfcp_erp_adisc(struct zfcp_port *port)
        if (send_els == NULL)
                goto nomem;
 
-       send_els->req = kzalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+       send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
        if (send_els->req == NULL)
                goto nomem;
+       sg_init_table(send_els->req, 1);
 
-       send_els->resp = kzalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+       send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
        if (send_els->resp == NULL)
                goto nomem;
+       sg_init_table(send_els->resp, 1);
 
        address = (void *) get_zeroed_page(GFP_ATOMIC);
        if (address == NULL)
@@ -363,7 +365,7 @@ zfcp_erp_adisc(struct zfcp_port *port)
        retval = -ENOMEM;
  freemem:
        if (address != NULL)
-               __free_pages(send_els->req->page, 0);
+               __free_pages(sg_page(send_els->req), 0);
        if (send_els != NULL) {
                kfree(send_els->req);
                kfree(send_els->resp);
@@ -437,7 +439,7 @@ zfcp_erp_adisc_handler(unsigned long data)
 
  out:
        zfcp_port_put(port);
-       __free_pages(send_els->req->page, 0);
+       __free_pages(sg_page(send_els->req), 0);
        kfree(send_els->req);
        kfree(send_els->resp);
        kfree(send_els);
index e7a1642..d4f8fcd 100644 (file)
@@ -134,7 +134,7 @@ int init_vfc_hw(struct vfc_dev *dev)
 int init_vfc_devstruct(struct vfc_dev *dev, int instance) 
 {
        dev->instance=instance;
-       init_MUTEX(&dev->device_lock_sem);
+       mutex_init(&dev->device_lock_mtx);
        dev->control_reg=0;
        dev->busy=0;
        return 0;
index fb14014..afb262b 100644 (file)
@@ -1840,7 +1840,7 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
                            (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) {
                                if (srb->sc_data_direction == DMA_TO_DEVICE || srb->sc_data_direction == DMA_BIDIRECTIONAL) {
                                        struct scatterlist *sg = scsi_sglist(srb);
-                                       char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+                                       char *buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
                                        memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length);
                                        kunmap_atomic(buf - sg->offset, KM_IRQ0);
                                }
@@ -1919,7 +1919,7 @@ static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int re
                        char *buf;
                        unsigned long flags = 0;
                        local_irq_save(flags);
-                       buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+                       buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
                        memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length);
                        kunmap_atomic(buf - sg->offset, KM_IRQ0);
                        local_irq_restore(flags);
index a64153b..59716eb 100644 (file)
@@ -1469,7 +1469,7 @@ static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id,
        struct scatterlist *sg = scsi_sglist(cmd);
 
        local_irq_save(flags);
-       buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+       buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
        transfer_len = min(sg->length, len);
 
        memcpy(buf, data, transfer_len);
index 988f0bc..2597209 100644 (file)
@@ -298,8 +298,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
        if (cmd->use_sg) {
                cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
                cmd->SCp.buffers_residual = cmd->use_sg - 1;
-               cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
-                              cmd->SCp.buffer->offset;
+               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
        } else {
                cmd->SCp.buffer = NULL;
@@ -2143,8 +2142,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                        ++cmd->SCp.buffer;
                                        --cmd->SCp.buffers_residual;
                                        cmd->SCp.this_residual = cmd->SCp.buffer->length;
-                                       cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
-                                                      cmd->SCp.buffer->offset;
+                                       cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                                        dprintk(NDEBUG_INFORMATION, ("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual));
                                }
                                /*
index 96e8e29..5b0efc9 100644 (file)
@@ -927,7 +927,7 @@ static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
                        esp->dma_mmu_get_scsi_sgl(esp, sp);
                else
                        sp->SCp.ptr =
-                               (char *) virt_to_phys((page_address(sp->SCp.buffer->page) + sp->SCp.buffer->offset));
+                               (char *) virt_to_phys(sg_virt(sp->SCp.buffer));
        }
 }
 
@@ -1748,7 +1748,7 @@ static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp)
        if (esp->dma_advance_sg)
                esp->dma_advance_sg (sp);
        else
-               sp->SCp.ptr = (char *) virt_to_phys((page_address(sp->SCp.buffer->page) + sp->SCp.buffer->offset));
+               sp->SCp.ptr = (char *) virt_to_phys(sg_virt(sp->SCp.buffer));
 
 }
 
index 3168a17..137d065 100644 (file)
@@ -875,8 +875,7 @@ static void NCR53c406a_intr(void *dev_id)
                        outb(TRANSFER_INFO | DMA_OP, CMD_REG);
 #if USE_PIO
                         scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
-                                NCR53c406a_pio_write(page_address(sg->page) + sg->offset,
-                                                     sg->length);
+                                NCR53c406a_pio_write(sg_virt(sg), sg->length);
                         }
                        REG0;
 #endif                         /* USE_PIO */
@@ -897,8 +896,7 @@ static void NCR53c406a_intr(void *dev_id)
                        outb(TRANSFER_INFO | DMA_OP, CMD_REG);
 #if USE_PIO
                         scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
-                                NCR53c406a_pio_read(page_address(sg->page) + sg->offset,
-                                                    sg->length);
+                                NCR53c406a_pio_read(sg_virt(sg), sg->length);
                         }
                        REG0;
 #endif                         /* USE_PIO */
index 80e448d..a77ab8d 100644 (file)
@@ -356,7 +356,7 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne
        int transfer_len;
        struct scatterlist *sg = scsi_sglist(scsicmd);
 
-       buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+       buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
        transfer_len = min(sg->length, len + offset);
 
        transfer_len -= offset;
index a58c265..ea8c699 100644 (file)
@@ -613,7 +613,7 @@ struct aha152x_scdata {
 #define SCNEXT(SCpnt)          SCDATA(SCpnt)->next
 #define SCSEM(SCpnt)           SCDATA(SCpnt)->done
 
-#define SG_ADDRESS(buffer)     ((char *) (page_address((buffer)->page)+(buffer)->offset))
+#define SG_ADDRESS(buffer)     ((char *) sg_virt((buffer)))
 
 /* state handling */
 static void seldi_run(struct Scsi_Host *shpnt);
index 961a188..bbcc2c5 100644 (file)
@@ -49,7 +49,7 @@
 #include "aha1542.h"
 
 #define SCSI_BUF_PA(address)   isa_virt_to_bus(address)
-#define SCSI_SG_PA(sgent)      (isa_page_to_bus((sgent)->page) + (sgent)->offset)
+#define SCSI_SG_PA(sgent)      (isa_page_to_bus(sg_page((sgent))) + (sgent)->offset)
 
 static void BAD_DMA(void *address, unsigned int length)
 {
@@ -66,8 +66,7 @@ static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
                       int badseg)
 {
        printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%llx length %u\n",
-              badseg, nseg,
-              page_address(sgp->page) + sgp->offset,
+              badseg, nseg, sg_virt(sgp),
               (unsigned long long)SCSI_SG_PA(sgp),
               sgp->length);
 
@@ -712,8 +711,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
                                printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
                                scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
                                        printk(KERN_CRIT "%d: %p %d\n", i,
-                                              (page_address(sg->page) +
-                                               sg->offset), sg->length);
+                                              sg_virt(sg), sg->length);
                                };
                                printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
                                ptr = (unsigned char *) &cptr[i];
index f817775..f7a2528 100644 (file)
@@ -1343,7 +1343,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
                                                /* 4 bytes: Areca io control code */
 
        sg = scsi_sglist(cmd);
-       buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+       buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
        if (scsi_sg_count(cmd) > 1) {
                retvalue = ARCMSR_MESSAGE_FAIL;
                goto message_out;
@@ -1593,7 +1593,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
                strncpy(&inqdata[32], "R001", 4); /* Product Revision */
 
                sg = scsi_sglist(cmd);
-               buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+               buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
 
                memcpy(buffer, inqdata, sizeof(inqdata));
                sg = scsi_sglist(cmd);
index 52d0b87..d178098 100644 (file)
@@ -515,8 +515,7 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
        if (cmd->use_sg) {
                cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
                cmd->SCp.buffers_residual = cmd->use_sg - 1;
-               cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page) +
-                              cmd->SCp.buffer->offset;
+               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
                /* ++roman: Try to merge some scatter-buffers if they are at
                 * contiguous physical addresses.
@@ -2054,8 +2053,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                        ++cmd->SCp.buffer;
                                        --cmd->SCp.buffers_residual;
                                        cmd->SCp.this_residual = cmd->SCp.buffer->length;
-                                       cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
-                                                  cmd->SCp.buffer->offset;
+                                       cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                                        /* ++roman: Try to merge some scatter-buffers if
                                         * they are at contiguous physical addresses.
                                         */
index 96180bb..982c509 100644 (file)
@@ -172,7 +172,7 @@ static void IncStat(struct scsi_pointer *SCp, unsigned int Increment)
                        SCp->Status = 0;
                else {
                        SCp->buffer++;
-                       SCp->ptr = page_address(SCp->buffer->page) + SCp->buffer->offset;
+                       SCp->ptr = sg_virt(SCp->buffer);
                        SCp->this_residual = SCp->buffer->length;
                }
        }
@@ -410,7 +410,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
        } else {
                cmd->SCp.buffer = cmd->request_buffer;
                cmd->SCp.buffers_residual = cmd->use_sg;
-               cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
        }
        cmd->SCp.Status = (cmd->SCp.this_residual != 0);        /* TRUE as long as bytes 
index 668569e..8335b60 100644 (file)
@@ -973,7 +973,7 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
                                if (current_SC->SCp.buffers_residual) {
                                        --current_SC->SCp.buffers_residual;
                                        ++current_SC->SCp.buffer;
-                                       current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+                                       current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
                                        current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
                                } else
                                        break;
@@ -1006,7 +1006,7 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
                        if (!current_SC->SCp.this_residual && current_SC->SCp.buffers_residual) {
                                --current_SC->SCp.buffers_residual;
                                ++current_SC->SCp.buffer;
-                               current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+                               current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
                                current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
                        }
                }
@@ -1109,7 +1109,7 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 
        if (current_SC->use_sg) {
                current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer;
-               current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+               current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
                current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
                current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
        } else {
index 5d282e6..2cd6b49 100644 (file)
@@ -1321,7 +1321,7 @@ static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
            if (current_SC->SCp.buffers_residual) {
               --current_SC->SCp.buffers_residual;
               ++current_SC->SCp.buffer;
-              current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+              current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
               current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
            } else
                  break;
@@ -1354,7 +1354,7 @@ static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
             && current_SC->SCp.buffers_residual) {
            --current_SC->SCp.buffers_residual;
            ++current_SC->SCp.buffer;
-           current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+           current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
            current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
         }
       }
@@ -1439,8 +1439,7 @@ static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
 
    if (scsi_sg_count(current_SC)) {
           current_SC->SCp.buffer = scsi_sglist(current_SC);
-          current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page)
-                  + current_SC->SCp.buffer->offset;
+          current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
           current_SC->SCp.this_residual    = current_SC->SCp.buffer->length;
           current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
    } else {
index 3ac080e..5ab3ce7 100644 (file)
@@ -2374,18 +2374,18 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
             if (cpsum+cpnow > cpcount) 
                 cpnow = cpcount - cpsum;
             cpsum += cpnow;
-            if (!sl->page) {
+            if (!sg_page(sl)) {
                 printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n",
                        ha->hanum);
                 return;
             }
             local_irq_save(flags);
-            address = kmap_atomic(sl->page, KM_BIO_SRC_IRQ) + sl->offset;
+            address = kmap_atomic(sg_page(sl), KM_BIO_SRC_IRQ) + sl->offset;
             if (to_buffer)
                 memcpy(buffer, address, cpnow);
             else
                 memcpy(address, buffer, cpnow);
-            flush_dcache_page(sl->page);
+            flush_dcache_page(sg_page(sl));
             kunmap_atomic(address, KM_BIO_SRC_IRQ);
             local_irq_restore(flags);
             if (cpsum == cpcount)
index 714e627..db004a4 100644 (file)
@@ -1828,7 +1828,7 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
                BUG_ON(scsi_sg_count(cmd) > 16);
 
                scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
-                       ld(shpnt)[ldn].sge[i].address = (void *) (isa_page_to_bus(sg->page) + sg->offset);
+                       ld(shpnt)[ldn].sge[i].address = (void *) (isa_page_to_bus(sg_page(sg)) + sg->offset);
                        ld(shpnt)[ldn].sge[i].byte_length = sg->length;
                }
                scb->enable |= IM_POINTER_TO_LIST;
index 252d180..8d0244c 100644 (file)
@@ -175,18 +175,18 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne
 
        while (bcount) {
                count = min(pc->sg->length - pc->b_count, bcount);
-               if (PageHighMem(pc->sg->page)) {
+               if (PageHighMem(sg_page(pc->sg))) {
                        unsigned long flags;
 
                        local_irq_save(flags);
-                       buf = kmap_atomic(pc->sg->page, KM_IRQ0) +
+                       buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +
                                        pc->sg->offset;
                        drive->hwif->atapi_input_bytes(drive,
                                                buf + pc->b_count, count);
                        kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
                        local_irq_restore(flags);
                } else {
-                       buf = page_address(pc->sg->page) + pc->sg->offset;
+                       buf = sg_virt(pc->sg);
                        drive->hwif->atapi_input_bytes(drive,
                                                buf + pc->b_count, count);
                }
@@ -212,18 +212,18 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
 
        while (bcount) {
                count = min(pc->sg->length - pc->b_count, bcount);
-               if (PageHighMem(pc->sg->page)) {
+               if (PageHighMem(sg_page(pc->sg))) {
                        unsigned long flags;
 
                        local_irq_save(flags);
-                       buf = kmap_atomic(pc->sg->page, KM_IRQ0) +
+                       buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +
                                                pc->sg->offset;
                        drive->hwif->atapi_output_bytes(drive,
                                                buf + pc->b_count, count);
                        kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
                        local_irq_restore(flags);
                } else {
-                       buf = page_address(pc->sg->page) + pc->sg->offset;
+                       buf = sg_virt(pc->sg);
                        drive->hwif->atapi_output_bytes(drive,
                                                buf + pc->b_count, count);
                }
index 74cdc1f..a3d0c6b 100644 (file)
@@ -705,9 +705,7 @@ static int imm_completion(struct scsi_cmnd *cmd)
                                cmd->SCp.buffer++;
                                cmd->SCp.this_residual =
                                    cmd->SCp.buffer->length;
-                               cmd->SCp.ptr =
-                                   page_address(cmd->SCp.buffer->page) +
-                                   cmd->SCp.buffer->offset;
+                               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
 
                                /*
                                 * Make sure that we transfer even number of bytes
@@ -844,9 +842,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
                        cmd->SCp.buffer =
                            (struct scatterlist *) cmd->request_buffer;
                        cmd->SCp.this_residual = cmd->SCp.buffer->length;
-                       cmd->SCp.ptr =
-                           page_address(cmd->SCp.buffer->page) +
-                           cmd->SCp.buffer->offset;
+                       cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                } else {
                        /* else fill the only available buffer */
                        cmd->SCp.buffer = NULL;
index ab7cbf3..c8b452f 100644 (file)
@@ -372,7 +372,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
        if (cmd->use_sg) {
                cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
                cmd->SCp.buffers_residual = cmd->use_sg - 1;
-               cmd->SCp.ptr = (char *) page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
        } else {
                cmd->SCp.buffer = NULL;
@@ -764,7 +764,7 @@ static void transfer_bytes(Scsi_Cmnd * cmd, int data_in_dir)
                ++cmd->SCp.buffer;
                --cmd->SCp.buffers_residual;
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
-               cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
        }
 
 /* Set up hardware registers */
index c316a0b..439b97a 100644 (file)
@@ -2872,6 +2872,7 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
        }
 
        scatterlist = sglist->scatterlist;
+       sg_init_table(scatterlist, num_elem);
 
        sglist->order = order;
        sglist->num_sg = num_elem;
@@ -2884,12 +2885,12 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
 
                        /* Free up what we already allocated */
                        for (j = i - 1; j >= 0; j--)
-                               __free_pages(scatterlist[j].page, order);
+                               __free_pages(sg_page(&scatterlist[j]), order);
                        kfree(sglist);
                        return NULL;
                }
 
-               scatterlist[i].page = page;
+               sg_set_page(&scatterlist[i], page);
        }
 
        return sglist;
@@ -2910,7 +2911,7 @@ static void ipr_free_ucode_buffer(struct ipr_sglist *sglist)
        int i;
 
        for (i = 0; i < sglist->num_sg; i++)
-               __free_pages(sglist->scatterlist[i].page, sglist->order);
+               __free_pages(sg_page(&sglist->scatterlist[i]), sglist->order);
 
        kfree(sglist);
 }
@@ -2940,9 +2941,11 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
        scatterlist = sglist->scatterlist;
 
        for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
-               kaddr = kmap(scatterlist[i].page);
+               struct page *page = sg_page(&scatterlist[i]);
+
+               kaddr = kmap(page);
                memcpy(kaddr, buffer, bsize_elem);
-               kunmap(scatterlist[i].page);
+               kunmap(page);
 
                scatterlist[i].length = bsize_elem;
 
@@ -2953,9 +2956,11 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
        }
 
        if (len % bsize_elem) {
-               kaddr = kmap(scatterlist[i].page);
+               struct page *page = sg_page(&scatterlist[i]);
+
+               kaddr = kmap(page);
                memcpy(kaddr, buffer, len % bsize_elem);
-               kunmap(scatterlist[i].page);
+               kunmap(page);
 
                scatterlist[i].length = len % bsize_elem;
        }
index edaac27..5c5a9b2 100644 (file)
@@ -1515,7 +1515,7 @@ static int ips_is_passthru(struct scsi_cmnd *SC)
                 /* kmap_atomic() ensures addressability of the user buffer.*/
                 /* local_irq_save() protects the KM_IRQ0 address slot.     */
                 local_irq_save(flags);
-                buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+                buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
                 if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
                     buffer[2] == 'P' && buffer[3] == 'P') {
                         kunmap_atomic(buffer - sg->offset, KM_IRQ0);
@@ -3523,7 +3523,7 @@ ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
                 /* kmap_atomic() ensures addressability of the data buffer.*/
                 /* local_irq_save() protects the KM_IRQ0 address slot.     */
                 local_irq_save(flags);
-                buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+                buffer = kmap_atomic(sg_page(&sg[i]), KM_IRQ0) + sg[i].offset;
                 memcpy(buffer, &cdata[xfer_cnt], min_cnt);
                 kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
                 local_irq_restore(flags);
@@ -3556,7 +3556,7 @@ ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
                 /* kmap_atomic() ensures addressability of the data buffer.*/
                 /* local_irq_save() protects the KM_IRQ0 address slot.     */
                 local_irq_save(flags);
-                buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+                buffer = kmap_atomic(sg_page(&sg[i]), KM_IRQ0) + sg[i].offset;
                 memcpy(&cdata[xfer_cnt], buffer, min_cnt);
                 kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
                 local_irq_restore(flags);
index a21455d..6ce4109 100644 (file)
@@ -70,9 +70,7 @@ module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
 static inline void
 iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
 {
-       ibuf->sg.page = virt_to_page(vbuf);
-       ibuf->sg.offset = offset_in_page(vbuf);
-       ibuf->sg.length = size;
+       sg_init_one(&ibuf->sg, vbuf, size);
        ibuf->sent = 0;
        ibuf->use_sendmsg = 1;
 }
@@ -80,13 +78,14 @@ iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
 static inline void
 iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
 {
-       ibuf->sg.page = sg->page;
+       sg_init_table(&ibuf->sg, 1);
+       sg_set_page(&ibuf->sg, sg_page(sg));
        ibuf->sg.offset = sg->offset;
        ibuf->sg.length = sg->length;
        /*
         * Fastpath: sg element fits into single page
         */
-       if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg->page))
+       if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg_page(sg)))
                ibuf->use_sendmsg = 0;
        else
                ibuf->use_sendmsg = 1;
@@ -716,7 +715,7 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
        for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) {
                char *dest;
 
-               dest = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
+               dest = kmap_atomic(sg_page(&sg[i]), KM_SOFTIRQ0);
                rc = iscsi_ctask_copy(tcp_conn, ctask, dest + sg[i].offset,
                                      sg[i].length, offset);
                kunmap_atomic(dest, KM_SOFTIRQ0);
@@ -1103,9 +1102,9 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
         * slab case.
         */
        if (buf->use_sendmsg)
-               res = sock_no_sendpage(sk, buf->sg.page, offset, size, flags);
+               res = sock_no_sendpage(sk, sg_page(&buf->sg), offset, size, flags);
        else
-               res = tcp_conn->sendpage(sk, buf->sg.page, offset, size, flags);
+               res = tcp_conn->sendpage(sk, sg_page(&buf->sg), offset, size, flags);
 
        if (res >= 0) {
                conn->txdata_octets += res;
index 10d1aff..66c6520 100644 (file)
@@ -658,7 +658,7 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
                        struct scatterlist *sg;
 
                        sg = scsi_sglist(cmd);
-                       buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+                       buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
 
                        memset(buf, 0, cmd->cmnd[4]);
                        kunmap_atomic(buf - sg->offset, KM_IRQ0);
@@ -1542,10 +1542,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
                if( cmd->cmnd[0] == INQUIRY && !islogical ) {
 
                        sgl = scsi_sglist(cmd);
-                       if( sgl->page ) {
-                               c = *(unsigned char *)
-                                       page_address((&sgl[0])->page) +
-                                       (&sgl[0])->offset; 
+                       if( sg_page(sgl) ) {
+                               c = *(unsigned char *) sg_virt(&sgl[0]);
                        } else {
                                printk(KERN_WARNING
                                       "megaraid: invalid sg.\n");
index 7877920..c892310 100644 (file)
@@ -1584,10 +1584,8 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
                        caddr_t                 vaddr;
 
                        sgl = scsi_sglist(scp);
-                       if (sgl->page) {
-                               vaddr = (caddr_t)
-                                       (page_address((&sgl[0])->page)
-                                        + (&sgl[0])->offset);
+                       if (sg_page(sgl)) {
+                               vaddr = (caddr_t) sg_virt(&sgl[0]);
 
                                memset(vaddr, 0, scp->cmnd[4]);
                        }
@@ -2328,10 +2326,8 @@ megaraid_mbox_dpc(unsigned long devp)
                                && IS_RAID_CH(raid_dev, scb->dev_channel)) {
 
                        sgl = scsi_sglist(scp);
-                       if (sgl->page) {
-                               c = *(unsigned char *)
-                                       (page_address((&sgl[0])->page) +
-                                        (&sgl[0])->offset);
+                       if (sg_page(sgl)) {
+                               c = *(unsigned char *) sg_virt(&sgl[0]);
                        } else {
                                con_log(CL_ANN, (KERN_WARNING
                                                 "megaraid mailbox: invalid sg:%d\n",
index 26a6d55..8e5eadb 100644 (file)
@@ -550,8 +550,7 @@ void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 
 void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
-        sp->SCp.ptr = page_address(sp->SCp.buffer->page)+
-                     sp->SCp.buffer->offset;
+        sp->SCp.ptr = sg_virt(sp->SCp.buffer);
 }
 
 void dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
@@ -564,8 +563,7 @@ void dma_mmu_release_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 
 void dma_advance_sg(Scsi_Cmnd *sp)
 {
-       sp->SCp.ptr = page_address(sp->SCp.buffer->page)+
-                     sp->SCp.buffer->offset;
+       sp->SCp.ptr = sg_virt(sp->SCp.buffer);
 }
 
 
index 331b789..1c5c4b6 100644 (file)
@@ -542,7 +542,7 @@ static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int q
        if (STp->raw) {
                if (STp->buffer->syscall_result) {
                        for (i=0; i < STp->buffer->sg_segs; i++)
-                               memset(page_address(STp->buffer->sg[i].page),
+                               memset(page_address(sg_page(&STp->buffer->sg[i])),
                                       0, STp->buffer->sg[i].length);
                        strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
                 } else
@@ -4437,7 +4437,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
                for (i = 0, b_size = 0; 
                     (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE); 
                     b_size += STp->buffer->sg[i++].length);
-               STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size);
+               STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size);
 #if DEBUG
                printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
                        STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
@@ -5252,25 +5252,26 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
        /* Try to allocate the first segment up to OS_DATA_SIZE and the others
           big enough to reach the goal (code assumes no segments in place) */
        for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
-               STbuffer->sg[0].page = alloc_pages(priority, order);
+               struct page *page = alloc_pages(priority, order);
+
                STbuffer->sg[0].offset = 0;
-               if (STbuffer->sg[0].page != NULL) {
+               if (page != NULL) {
+                   sg_set_page(&STbuffer->sg[0], page);
                    STbuffer->sg[0].length = b_size;
-                   STbuffer->b_data = page_address(STbuffer->sg[0].page);
+                   STbuffer->b_data = page_address(page);
                    break;
                }
        }
-       if (STbuffer->sg[0].page == NULL) {
+       if (sg_page(&STbuffer->sg[0]) == NULL) {
                printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
                return 0;
        }
        /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
        for (segs=STbuffer->sg_segs=1, got=b_size;
             segs < max_segs && got < OS_FRAME_SIZE; ) {
-               STbuffer->sg[segs].page =
-                               alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
+               struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
                STbuffer->sg[segs].offset = 0;
-               if (STbuffer->sg[segs].page == NULL) {
+               if (page == NULL) {
                        if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
                                b_size /= 2;  /* Large enough for the rest of the buffers */
                                order--;
@@ -5284,6 +5285,7 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
                        normalize_buffer(STbuffer);
                        return 0;
                }
+               sg_set_page(&STbuffer->sg[segs], page);
                STbuffer->sg[segs].length = (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size;
                got += STbuffer->sg[segs].length;
                STbuffer->buffer_size = got;
@@ -5316,7 +5318,7 @@ static void normalize_buffer(struct osst_buffer *STbuffer)
                     b_size < STbuffer->sg[i].length;
                     b_size *= 2, order++);
 
-               __free_pages(STbuffer->sg[i].page, order);
+               __free_pages(sg_page(&STbuffer->sg[i]), order);
                STbuffer->buffer_size -= STbuffer->sg[i].length;
        }
 #if DEBUG
@@ -5344,7 +5346,7 @@ static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, i
        for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
                cnt = st_bp->sg[i].length - offset < do_count ?
                      st_bp->sg[i].length - offset : do_count;
-               res = copy_from_user(page_address(st_bp->sg[i].page) + offset, ubp, cnt);
+               res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt);
                if (res)
                        return (-EFAULT);
                do_count -= cnt;
@@ -5377,7 +5379,7 @@ static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count
        for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
                cnt = st_bp->sg[i].length - offset < do_count ?
                      st_bp->sg[i].length - offset : do_count;
-               res = copy_to_user(ubp, page_address(st_bp->sg[i].page) + offset, cnt);
+               res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt);
                if (res)
                        return (-EFAULT);
                do_count -= cnt;
@@ -5410,7 +5412,7 @@ static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
             i < st_bp->sg_segs && do_count > 0; i++) {
                cnt = st_bp->sg[i].length - offset < do_count ?
                      st_bp->sg[i].length - offset : do_count ;
-               memset(page_address(st_bp->sg[i].page) + offset, 0, cnt);
+               memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt);
                do_count -= cnt;
                offset = 0;
        }
@@ -5430,7 +5432,7 @@ static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
        for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
                cnt = st_bp->sg[i].length < do_count ?
                      st_bp->sg[i].length : do_count ;
-               memcpy(page_address(st_bp->sg[i].page), ptr, cnt);
+               memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt);
                do_count -= cnt;
                ptr      += cnt;
        }
@@ -5451,7 +5453,7 @@ static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
        for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
                cnt = st_bp->sg[i].length < do_count ?
                      st_bp->sg[i].length : do_count ;
-               memcpy(ptr, page_address(st_bp->sg[i].page), cnt);
+               memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt);
                do_count -= cnt;
                ptr      += cnt;
        }
index 9839755..7db28cd 100644 (file)
@@ -393,7 +393,7 @@ enum _burst_mode {
 #define MSG_EXT_SDTR         0x01
 
 /* scatter-gather table */
-#  define BUFFER_ADDR ((char *)((unsigned int)(SCpnt->SCp.buffer->page) + SCpnt->SCp.buffer->offset))
+#  define BUFFER_ADDR ((char *)((sg_virt(SCpnt->SCp.buffer))))
 
 #endif  /*__nsp_cs__*/
 /* end */
index 190e2a7..969b938 100644 (file)
@@ -443,8 +443,7 @@ SYM53C500_intr(int irq, void *dev_id)
 
                        scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) {
                                SYM53C500_pio_write(fast_pio, port_base,
-                                                   page_address(sg->page) + sg->offset,
-                                                   sg->length);
+                                   sg_virt(sg), sg->length);
                        }
                        REG0(port_base);
                }
@@ -463,8 +462,7 @@ SYM53C500_intr(int irq, void *dev_id)
 
                        scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) {
                                SYM53C500_pio_read(fast_pio, port_base,
-                                                  page_address(sg->page) + sg->offset,
-                                                  sg->length);
+                                       sg_virt(sg), sg->length);
                        }
                        REG0(port_base);
                }
index 67b6d76..67ee51a 100644 (file)
@@ -608,9 +608,7 @@ static int ppa_completion(struct scsi_cmnd *cmd)
                                cmd->SCp.buffer++;
                                cmd->SCp.this_residual =
                                    cmd->SCp.buffer->length;
-                               cmd->SCp.ptr =
-                                   page_address(cmd->SCp.buffer->page) +
-                                   cmd->SCp.buffer->offset;
+                               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                        }
                }
                /* Now check to see if the drive is ready to comunicate */
@@ -756,8 +754,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
                        /* if many buffers are available, start filling the first */
                        cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
                        cmd->SCp.this_residual = cmd->SCp.buffer->length;
-                       cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
-                           cmd->SCp.buffer->offset;
+                       cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                } else {
                        /* else fill the only available buffer */
                        cmd->SCp.buffer = NULL;
index 0f43d1d..17b4a7c 100644 (file)
@@ -111,14 +111,14 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
        req_len = act_len = 0;
        scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) {
                if (active) {
-                       kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+                       kaddr = kmap_atomic(sg_page(sgpnt), KM_IRQ0);
                        len = sgpnt->length;
                        if ((req_len + len) > buflen) {
                                active = 0;
                                len = buflen - req_len;
                        }
                        memcpy(kaddr + sgpnt->offset, buf + req_len, len);
-                       flush_kernel_dcache_page(sgpnt->page);
+                       flush_kernel_dcache_page(sg_page(sgpnt));
                        kunmap_atomic(kaddr, KM_IRQ0);
                        act_len += len;
                }
@@ -147,7 +147,7 @@ static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf)
 
        req_len = fin = 0;
        scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) {
-               kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+               kaddr = kmap_atomic(sg_page(sgpnt), KM_IRQ0);
                len = sgpnt->length;
                if ((req_len + len) > buflen) {
                        len = buflen - req_len;
index 2bfbf26..de7b3bc 100644 (file)
@@ -317,7 +317,7 @@ static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
                                return ((priv->qabort == 1 ?
                                         DID_ABORT : DID_RESET) << 16);
                        }
-                       buf = page_address(sg->page) + sg->offset;
+                       buf = sg_virt(sg);
                        if (ql_pdma(priv, phase, buf, sg->length))
                                break;
                }
index 72ee4c9..46cae5a 100644 (file)
@@ -625,7 +625,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
        scsi_for_each_sg(scp, sg, scp->use_sg, k) {
                if (active) {
                        kaddr = (unsigned char *)
-                               kmap_atomic(sg->page, KM_USER0);
+                               kmap_atomic(sg_page(sg), KM_USER0);
                        if (NULL == kaddr)
                                return (DID_ERROR << 16);
                        kaddr_off = (unsigned char *)kaddr + sg->offset;
@@ -672,7 +672,7 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
        sg = scsi_sglist(scp);
        req_len = fin = 0;
        for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) {
-               kaddr = (unsigned char *)kmap_atomic(sg->page, KM_USER0);
+               kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
                if (NULL == kaddr)
                        return -1;
                kaddr_off = (unsigned char *)kaddr + sg->offset;
index aac8a02..61fdaf0 100644 (file)
@@ -295,7 +295,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
        int i, err, nr_vecs = 0;
 
        for_each_sg(sgl, sg, nsegs, i) {
-               page = sg->page;
+               page = sg_page(sg);
                off = sg->offset;
                len = sg->length;
                data_len += len;
@@ -764,7 +764,7 @@ struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
                if (unlikely(!sgl))
                        goto enomem;
 
-               memset(sgl, 0, sizeof(*sgl) * sgp->size);
+               sg_init_table(sgl, sgp->size);
 
                /*
                 * first loop through, set initial index and return value
@@ -780,6 +780,13 @@ struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
                if (prev)
                        sg_chain(prev, SCSI_MAX_SG_SEGMENTS, sgl);
 
+               /*
+                * if we have nothing left, mark the last segment as
+                * end-of-list
+                */
+               if (!left)
+                       sg_mark_end(sgl, this);
+
                /*
                 * don't allow subsequent mempool allocs to sleep, it would
                 * violate the mempool principle.
@@ -2353,7 +2360,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count,
        *offset = *offset - len_complete + sg->offset;
 
        /* Assumption: contiguous pages can be accessed as "page + i" */
-       page = nth_page(sg->page, (*offset >> PAGE_SHIFT));
+       page = nth_page(sg_page(sg), (*offset >> PAGE_SHIFT));
        *offset &= ~PAGE_MASK;
 
        /* Bytes in this sg-entry from *offset to the end of the page */
index ce80fa9..b113244 100644 (file)
@@ -999,14 +999,14 @@ connect_loop:
                                for (i = 0; i < nobuffs; ++i)
                                        printk("scsi%d : buffer %d address = %p length = %d\n",
                                             hostno, i,
-                                            page_address(buffer[i].page) + buffer[i].offset,
+                                            sg_virt(&buffer[i]),
                                             buffer[i].length);
                        }
 #endif
 
                        buffer = (struct scatterlist *) SCint->request_buffer;
                        len = buffer->length;
-                       data = page_address(buffer->page) + buffer->offset;
+                       data = sg_virt(buffer);
                } else {
                        DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno);
                        buffer = NULL;
@@ -1239,7 +1239,7 @@ connect_loop:
                                        --nobuffs;
                                        ++buffer;
                                        len = buffer->length;
-                                       data = page_address(buffer->page) + buffer->offset;
+                                       data = sg_virt(buffer);
                                        DPRINTK (DEBUG_SG,
                                                 "scsi%d : next scatter-gather buffer len = %d address = %08x\n",
                                                 hostno, len, data);
@@ -1396,7 +1396,7 @@ connect_loop:
                                        --nobuffs;
                                        ++buffer;
                                        len = buffer->length;
-                                       data = page_address(buffer->page) + buffer->offset;
+                                       data = sg_virt(buffer);
                                        DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);
                                }
                                break;
index 7238b2d..cc19710 100644 (file)
@@ -1169,7 +1169,7 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type)
                len = vma->vm_end - sa;
                len = (len < sg->length) ? len : sg->length;
                if (offset < len) {
-                       page = virt_to_page(page_address(sg->page) + offset);
+                       page = virt_to_page(page_address(sg_page(sg)) + offset);
                        get_page(page); /* increment page count */
                        break;
                }
@@ -1717,13 +1717,13 @@ st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
                   goto out_unlock; */
         }
 
-       sgl[0].page = pages[0];
+       sg_set_page(sgl, pages[0]);
        sgl[0].offset = uaddr & ~PAGE_MASK;
        if (nr_pages > 1) {
                sgl[0].length = PAGE_SIZE - sgl[0].offset;
                count -= sgl[0].length;
                for (i=1; i < nr_pages ; i++) {
-                       sgl[i].page = pages[i]; 
+                       sg_set_page(&sgl[i], pages[i]);
                        sgl[i].length = count < PAGE_SIZE ? count : PAGE_SIZE;
                        count -= PAGE_SIZE;
                }
@@ -1754,7 +1754,7 @@ st_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages,
        int i;
 
        for (i=0; i < nr_pages; i++) {
-               struct page *page = sgl[i].page;
+               struct page *page = sg_page(&sgl[i]);
 
                if (dirtied)
                        SetPageDirty(page);
@@ -1854,7 +1854,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
                                scatter_elem_sz_prev = ret_sz;
                        }
                }
-               sg->page = p;
+               sg_set_page(sg, p);
                sg->length = (ret_sz > num) ? num : ret_sz;
 
                SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k=%d, num=%d, "
@@ -1907,14 +1907,14 @@ sg_write_xfer(Sg_request * srp)
                onum = 1;
 
        ksglen = sg->length;
-       p = page_address(sg->page);
+       p = page_address(sg_page(sg));
        for (j = 0, k = 0; j < onum; ++j) {
                res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
                if (res)
                        return res;
 
                for (; p; sg = sg_next(sg), ksglen = sg->length,
-                    p = page_address(sg->page)) {
+                    p = page_address(sg_page(sg))) {
                        if (usglen <= 0)
                                break;
                        if (ksglen > usglen) {
@@ -1991,12 +1991,12 @@ sg_remove_scat(Sg_scatter_hold * schp)
                } else {
                        int k;
 
-                       for (k = 0; (k < schp->k_use_sg) && sg->page;
+                       for (k = 0; (k < schp->k_use_sg) && sg_page(sg);
                             ++k, sg = sg_next(sg)) {
                                SCSI_LOG_TIMEOUT(5, printk(
                                    "sg_remove_scat: k=%d, pg=0x%p, len=%d\n",
-                                   k, sg->page, sg->length));
-                               sg_page_free(sg->page, sg->length);
+                                   k, sg_page(sg), sg->length));
+                               sg_page_free(sg_page(sg), sg->length);
                        }
                }
                kfree(schp->buffer);
@@ -2038,7 +2038,7 @@ sg_read_xfer(Sg_request * srp)
        } else
                onum = 1;
 
-       p = page_address(sg->page);
+       p = page_address(sg_page(sg));
        ksglen = sg->length;
        for (j = 0, k = 0; j < onum; ++j) {
                res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
@@ -2046,7 +2046,7 @@ sg_read_xfer(Sg_request * srp)
                        return res;
 
                for (; p; sg = sg_next(sg), ksglen = sg->length,
-                    p = page_address(sg->page)) {
+                    p = page_address(sg_page(sg))) {
                        if (usglen <= 0)
                                break;
                        if (ksglen > usglen) {
@@ -2092,15 +2092,15 @@ sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer)
        if ((!outp) || (num_read_xfer <= 0))
                return 0;
 
-       for (k = 0; (k < schp->k_use_sg) && sg->page; ++k, sg = sg_next(sg)) {
+       for (k = 0; (k < schp->k_use_sg) && sg_page(sg); ++k, sg = sg_next(sg)) {
                num = sg->length;
                if (num > num_read_xfer) {
-                       if (__copy_to_user(outp, page_address(sg->page),
+                       if (__copy_to_user(outp, page_address(sg_page(sg)),
                                           num_read_xfer))
                                return -EFAULT;
                        break;
                } else {
-                       if (__copy_to_user(outp, page_address(sg->page),
+                       if (__copy_to_user(outp, page_address(sg_page(sg)),
                                           num))
                                return -EFAULT;
                        num_read_xfer -= num;
index 73c44cb..ce69b9e 100644 (file)
@@ -3797,7 +3797,7 @@ static void buf_to_sg(struct st_buffer *STbp, unsigned int length)
        sg = &(STbp->sg[0]);
        frp = STbp->frp;
        for (i=count=0; count < length; i++) {
-               sg[i].page = frp[i].page;
+               sg_set_page(&sg[i], frp[i].page);
                if (length - count > frp[i].length)
                        sg[i].length = frp[i].length;
                else
@@ -4446,14 +4446,14 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa
         }
 
        /* Populate the scatter/gather list */
-       sgl[0].page = pages[0]; 
+       sg_set_page(&sgl[0], pages[0]);
        sgl[0].offset = uaddr & ~PAGE_MASK;
        if (nr_pages > 1) {
                sgl[0].length = PAGE_SIZE - sgl[0].offset;
                count -= sgl[0].length;
                for (i=1; i < nr_pages ; i++) {
+                       sg_set_page(&sgl[i], pages[i]);;
                        sgl[i].offset = 0;
-                       sgl[i].page = pages[i]; 
                        sgl[i].length = count < PAGE_SIZE ? count : PAGE_SIZE;
                        count -= PAGE_SIZE;
                }
@@ -4483,7 +4483,7 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p
        int i;
 
        for (i=0; i < nr_pages; i++) {
-               struct page *page = sgl[i].page;
+               struct page *page = sg_page(&sgl[i]);
 
                if (dirtied)
                        SetPageDirty(page);
index 4aafe89..2dcde37 100644 (file)
@@ -272,8 +272,7 @@ static struct scsi_host_template *the_template = NULL;
 #define        HOSTNO          instance->host_no
 #define        H_NO(cmd)       (cmd)->device->host->host_no
 
-#define SGADDR(buffer) (void *)(((unsigned long)page_address((buffer)->page)) + \
-                       (buffer)->offset)
+#define SGADDR(buffer) (void *)(((unsigned long)sg_virt(((buffer)))))
 
 #ifdef SUPPORT_TAGS
 
index 8befab7..90cee94 100644 (file)
@@ -196,7 +196,7 @@ static unsigned int sym53c416_base_3[2] = {0,0};
 
 #define MAXHOSTS 4
 
-#define SG_ADDRESS(buffer)     ((char *) (page_address((buffer)->page)+(buffer)->offset))
+#define SG_ADDRESS(buffer)     ((char *) sg_virt((buffer)))
 
 enum phases
 {
index 5c72ca3..4419304 100644 (file)
@@ -430,10 +430,7 @@ static __inline__ void dc390_Going_remove (struct dc390_dcb* pDCB, struct dc390_
 
 static struct scatterlist* dc390_sg_build_single(struct scatterlist *sg, void *addr, unsigned int length)
 {
-       memset(sg, 0, sizeof(struct scatterlist));
-       sg->page        = virt_to_page(addr);
-       sg->length      = length;
-       sg->offset      = (unsigned long)addr & ~PAGE_MASK;
+       sg_init_one(sg, addr, length);
        return sg;
 }
 
index ea72bbe..6d1f0ed 100644 (file)
@@ -681,7 +681,7 @@ static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
 
        max = scsi_sg_count(SCpnt);
        scsi_for_each_sg(SCpnt, sg, max, i) {
-               mscp->sglist[i].address = isa_page_to_bus(sg->page) + sg->offset;
+               mscp->sglist[i].address = isa_page_to_bus(sg_page(sg)) + sg->offset;
                mscp->sglist[i].num_bytes = sg->length;
                transfer_length += sg->length;
        }
index 0e8e642..fdbb92d 100644 (file)
@@ -410,8 +410,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
        if (cmd->use_sg) {
                cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
                cmd->SCp.buffers_residual = cmd->use_sg - 1;
-               cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
-                   cmd->SCp.buffer->offset;
+               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
        } else {
                cmd->SCp.buffer = NULL;
@@ -745,8 +744,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
                ++cmd->SCp.buffer;
                --cmd->SCp.buffers_residual;
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
-               cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
-                   cmd->SCp.buffer->offset;
+               cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
        }
        if (!cmd->SCp.this_residual) /* avoid bogus setups */
                return;
index 255c611..03cd44f 100644 (file)
@@ -1123,7 +1123,7 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
                any2scsi(scb->maxlen, nseg * sizeof(Sgb));
 
                scsi_for_each_sg(SCpnt, sg, nseg, i) {
-                       any2scsi(sgb[i].ptr, isa_page_to_bus(sg->page) + sg->offset);
+                       any2scsi(sgb[i].ptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
                        any2scsi(sgb[i].len, sg->length);
                }
        } else {
index 87665d7..ed438bc 100644 (file)
@@ -624,7 +624,7 @@ choice
 
 config SERIAL_BFIN_DMA
        bool "DMA mode"
-       depends on DMA_UNCACHED_1M && !KGDB_UART
+       depends on !DMA_UNCACHED_NONE && !KGDB_UART
        help
          This driver works under DMA mode. If this option is selected, the
          blackfin simple dma driver is also enabled.
diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c
new file mode 100644 (file)
index 0000000..a7d4360
--- /dev/null
@@ -0,0 +1,653 @@
+/****************************************************************************/
+
+/*
+ *     mcf.c -- Freescale ColdFire UART driver
+ *
+ *     (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/nettel.h>
+
+/****************************************************************************/
+
+/*
+ *     Some boards implement the DTR/DCD lines using GPIO lines, most
+ *     don't. Dummy out the access macros for those that don't. Those
+ *     that do should define these macros somewhere in there board
+ *     specific inlude files.
+ */
+#if !defined(mcf_getppdcd)
+#define        mcf_getppdcd(p)         (1)
+#endif
+#if !defined(mcf_getppdtr)
+#define        mcf_getppdtr(p)         (1)
+#endif
+#if !defined(mcf_setppdtr)
+#define        mcf_setppdtr(p, v)      do { } while (0)
+#endif
+
+/****************************************************************************/
+
+/*
+ *     Local per-uart structure.
+ */
+struct mcf_uart {
+       struct uart_port        port;
+       unsigned int            sigs;           /* Local copy of line sigs */
+       unsigned char           imr;            /* Local IMR mirror */
+};
+
+/****************************************************************************/
+
+static unsigned int mcf_tx_empty(struct uart_port *port)
+{
+       return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
+               TIOCSER_TEMT : 0;
+}
+
+/****************************************************************************/
+
+static unsigned int mcf_get_mctrl(struct uart_port *port)
+{
+       struct mcf_uart *pp = (struct mcf_uart *) port;
+       unsigned long flags;
+       unsigned int sigs;
+
+       spin_lock_irqsave(&port->lock, flags);
+       sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
+               0 : TIOCM_CTS;
+       sigs |= (pp->sigs & TIOCM_RTS);
+       sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
+       sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return sigs;
+}
+
+/****************************************************************************/
+
+static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
+{
+       struct mcf_uart *pp = (struct mcf_uart *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       pp->sigs = sigs;
+       mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
+       if (sigs & TIOCM_RTS)
+               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
+       else
+               writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_start_tx(struct uart_port *port)
+{
+       struct mcf_uart *pp = (struct mcf_uart *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       pp->imr |= MCFUART_UIR_TXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_stop_tx(struct uart_port *port)
+{
+       struct mcf_uart *pp = (struct mcf_uart *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       pp->imr &= ~MCFUART_UIR_TXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_stop_rx(struct uart_port *port)
+{
+       struct mcf_uart *pp = (struct mcf_uart *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       pp->imr &= ~MCFUART_UIR_RXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (break_state == -1)
+               writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
+       else
+               writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_enable_ms(struct uart_port *port)
+{
+}
+
+/****************************************************************************/
+
+static int mcf_startup(struct uart_port *port)
+{
+       struct mcf_uart *pp = (struct mcf_uart *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Reset UART, get it into known state... */
+       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+       /* Enable the UART transmitter and receiver */
+       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
+               port->membase + MCFUART_UCR);
+
+       /* Enable RX interrupts now */
+       pp->imr = MCFUART_UIR_RXREADY;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_shutdown(struct uart_port *port)
+{
+       struct mcf_uart *pp = (struct mcf_uart *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Disable all interrupts now */
+       pp->imr = 0;
+       writeb(pp->imr, port->membase + MCFUART_UIMR);
+
+       /* Disable UART transmitter and receiver */
+       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
+       struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, baudclk;
+       unsigned char mr1, mr2;
+
+       baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+       baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
+
+       mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
+       mr2 = 0;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5: mr1 |= MCFUART_MR1_CS5; break;
+       case CS6: mr1 |= MCFUART_MR1_CS6; break;
+       case CS7: mr1 |= MCFUART_MR1_CS7; break;
+       case CS8:
+       default:  mr1 |= MCFUART_MR1_CS8; break;
+       }
+
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & CMSPAR) {
+                       if (termios->c_cflag & PARODD)
+                               mr1 |= MCFUART_MR1_PARITYMARK;
+                       else
+                               mr1 |= MCFUART_MR1_PARITYSPACE;
+               } else {
+                       if (termios->c_cflag & PARODD)
+                               mr1 |= MCFUART_MR1_PARITYODD;
+                       else
+                               mr1 |= MCFUART_MR1_PARITYEVEN;
+               }
+       } else {
+               mr1 |= MCFUART_MR1_PARITYNONE;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               mr2 |= MCFUART_MR2_STOP2;
+       else
+               mr2 |= MCFUART_MR2_STOP1;
+
+       if (termios->c_cflag & CRTSCTS) {
+               mr1 |= MCFUART_MR1_RXRTS;
+               mr2 |= MCFUART_MR2_TXCTS;
+       }
+
+       spin_lock_irqsave(&port->lock, flags);
+       writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+       writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
+       writeb(mr1, port->membase + MCFUART_UMR);
+       writeb(mr2, port->membase + MCFUART_UMR);
+       writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
+       writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
+       writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
+               port->membase + MCFUART_UCSR);
+       writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
+               port->membase + MCFUART_UCR);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_rx_chars(struct mcf_uart *pp)
+{
+       struct uart_port *port = (struct uart_port *) pp;
+       unsigned char status, ch, flag;
+
+       while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
+               ch = readb(port->membase + MCFUART_URB);
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (status & MCFUART_USR_RXERR) {
+                       writeb(MCFUART_UCR_CMDRESETERR,
+                               port->membase + MCFUART_UCR);
+
+                       if (status & MCFUART_USR_RXBREAK) {
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       } else if (status & MCFUART_USR_RXPARITY) {
+                               port->icount.parity++;
+                       } else if (status & MCFUART_USR_RXOVERRUN) {
+                               port->icount.overrun++;
+                       } else if (status & MCFUART_USR_RXFRAMING) {
+                               port->icount.frame++;
+                       }
+
+                       status &= port->read_status_mask;
+
+                       if (status & MCFUART_USR_RXBREAK)
+                               flag = TTY_BREAK;
+                       else if (status & MCFUART_USR_RXPARITY)
+                               flag = TTY_PARITY;
+                       else if (status & MCFUART_USR_RXFRAMING)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+               uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
+       }
+
+       tty_flip_buffer_push(port->info->tty);
+}
+
+/****************************************************************************/
+
+static void mcf_tx_chars(struct mcf_uart *pp)
+{
+       struct uart_port *port = (struct uart_port *) pp;
+       struct circ_buf *xmit = &port->info->xmit;
+
+       if (port->x_char) {
+               /* Send special char - probably flow control */
+               writeb(port->x_char, port->membase + MCFUART_UTB);
+               port->x_char = 0;
+               port->icount.tx++;
+               return;
+       }
+
+       while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
+               if (xmit->head == xmit->tail)
+                       break;
+               writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (xmit->head == xmit->tail) {
+               pp->imr &= ~MCFUART_UIR_TXREADY;
+               writeb(pp->imr, port->membase + MCFUART_UIMR);
+       }
+}
+
+/****************************************************************************/
+
+static irqreturn_t mcf_interrupt(int irq, void *data)
+{
+       struct uart_port *port = data;
+       struct mcf_uart *pp = (struct mcf_uart *) port;
+       unsigned int isr;
+
+       isr = readb(port->membase + MCFUART_UISR) & pp->imr;
+       if (isr & MCFUART_UIR_RXREADY)
+               mcf_rx_chars(pp);
+       if (isr & MCFUART_UIR_TXREADY)
+               mcf_tx_chars(pp);
+       return IRQ_HANDLED;
+}
+
+/****************************************************************************/
+
+static void mcf_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_MCF;
+
+       /* Clear mask, so no surprise interrupts. */
+       writeb(0, port->membase + MCFUART_UIMR);
+
+       if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
+               printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
+                       "interrupt vector=%d\n", port->line, port->irq);
+}
+
+/****************************************************************************/
+
+static const char *mcf_type(struct uart_port *port)
+{
+       return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
+}
+
+/****************************************************************************/
+
+static int mcf_request_port(struct uart_port *port)
+{
+       /* UARTs always present */
+       return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_release_port(struct uart_port *port)
+{
+       /* Nothing to release... */
+}
+
+/****************************************************************************/
+
+static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
+               return -EINVAL;
+       return 0;
+}
+
+/****************************************************************************/
+
+/*
+ *     Define the basic serial functions we support.
+ */
+static struct uart_ops mcf_uart_ops = {
+       .tx_empty       = mcf_tx_empty,
+       .get_mctrl      = mcf_get_mctrl,
+       .set_mctrl      = mcf_set_mctrl,
+       .start_tx       = mcf_start_tx,
+       .stop_tx        = mcf_stop_tx,
+       .stop_rx        = mcf_stop_rx,
+       .enable_ms      = mcf_enable_ms,
+       .break_ctl      = mcf_break_ctl,
+       .startup        = mcf_startup,
+       .shutdown       = mcf_shutdown,
+       .set_termios    = mcf_set_termios,
+       .type           = mcf_type,
+       .request_port   = mcf_request_port,
+       .release_port   = mcf_release_port,
+       .config_port    = mcf_config_port,
+       .verify_port    = mcf_verify_port,
+};
+
+static struct mcf_uart mcf_ports[3];
+
+#define        MCF_MAXPORTS    (sizeof(mcf_ports) / sizeof(struct mcf_uart))
+
+/****************************************************************************/
+#if defined(CONFIG_SERIAL_MCF_CONSOLE)
+/****************************************************************************/
+
+int __init early_mcf_setup(struct mcf_platform_uart *platp)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
+               port = &mcf_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_MCF;
+               port->mapbase = platp[i].mapbase;
+               port->membase = (platp[i].membase) ? platp[i].membase :
+                       (unsigned char __iomem *) port->mapbase;
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->uartclk = MCF_BUSCLK;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+               port->ops = &mcf_uart_ops;
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_console_putc(struct console *co, const char c)
+{
+       struct uart_port *port = &(mcf_ports + co->index)->port;
+       int i;
+
+       for (i = 0; (i < 0x10000); i++) {
+               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
+                       break;
+       }
+       writeb(c, port->membase + MCFUART_UTB);
+       for (i = 0; (i < 0x10000); i++) {
+               if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
+                       break;
+       }
+}
+
+/****************************************************************************/
+
+static void mcf_console_write(struct console *co, const char *s, unsigned int count)
+{
+       for (; (count); count--, s++) {
+               mcf_console_putc(co, *s);
+               if (*s == '\n')
+                       mcf_console_putc(co, '\r');
+       }
+}
+
+/****************************************************************************/
+
+static int __init mcf_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = CONFIG_SERIAL_MCF_BAUDRATE;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if ((co->index >= 0) && (co->index <= MCF_MAXPORTS))
+               co->index = 0;
+       port = &mcf_ports[co->index].port;
+       if (port->membase == 0)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+/****************************************************************************/
+
+static struct uart_driver mcf_driver;
+
+static struct console mcf_console = {
+       .name           = "ttyS",
+       .write          = mcf_console_write,
+       .device         = uart_console_device,
+       .setup          = mcf_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &mcf_driver,
+};
+
+static int __init mcf_console_init(void)
+{
+       register_console(&mcf_console);
+       return 0;
+}
+
+console_initcall(mcf_console_init);
+
+#define        MCF_CONSOLE     &mcf_console
+
+/****************************************************************************/
+#else
+/****************************************************************************/
+
+#define        MCF_CONSOLE     NULL
+
+/****************************************************************************/
+#endif /* CONFIG_MCF_CONSOLE */
+/****************************************************************************/
+
+/*
+ *     Define the mcf UART driver structure.
+ */
+static struct uart_driver mcf_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "mcf",
+       .dev_name       = "ttyS",
+       .major          = TTY_MAJOR,
+       .minor          = 64,
+       .nr             = MCF_MAXPORTS,
+       .cons           = MCF_CONSOLE,
+};
+
+/****************************************************************************/
+
+static int __devinit mcf_probe(struct platform_device *pdev)
+{
+       struct mcf_platform_uart *platp = pdev->dev.platform_data;
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
+               port = &mcf_ports[i].port;
+
+               port->line = i;
+               port->type = PORT_MCF;
+               port->mapbase = platp[i].mapbase;
+               port->membase = (platp[i].membase) ? platp[i].membase :
+                       (unsigned char __iomem *) platp[i].mapbase;
+               port->iotype = SERIAL_IO_MEM;
+               port->irq = platp[i].irq;
+               port->uartclk = MCF_BUSCLK;
+               port->ops = &mcf_uart_ops;
+               port->flags = ASYNC_BOOT_AUTOCONF;
+
+               uart_add_one_port(&mcf_driver, port);
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static int mcf_remove(struct platform_device *pdev)
+{
+       struct uart_port *port;
+       int i;
+
+       for (i = 0; (i < MCF_MAXPORTS); i++) {
+               port = &mcf_ports[i].port;
+               if (port)
+                       uart_remove_one_port(&mcf_driver, port);
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+
+static struct platform_driver mcf_platform_driver = {
+       .probe          = mcf_probe,
+       .remove         = __devexit_p(mcf_remove),
+       .driver         = {
+               .name   = "mcfuart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+/****************************************************************************/
+
+static int __init mcf_init(void)
+{
+       int rc;
+
+       printk("ColdFire internal UART serial driver\n");
+
+       rc = uart_register_driver(&mcf_driver);
+       if (rc)
+               return rc;
+       rc = platform_driver_register(&mcf_platform_driver);
+       if (rc)
+               return rc;
+       return 0;
+}
+
+/****************************************************************************/
+
+static void __exit mcf_exit(void)
+{
+       platform_driver_unregister(&mcf_platform_driver);
+       uart_unregister_driver(&mcf_driver);
+}
+
+/****************************************************************************/
+
+module_init(mcf_init);
+module_exit(mcf_exit);
+
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_DESCRIPTION("Freescale ColdFire UART driver");
+MODULE_LICENSE("GPL");
+
+/****************************************************************************/
index 8dd5a6a..8bdaa15 100644 (file)
@@ -11,9 +11,9 @@
 #include <linux/timer.h>
 #include <linux/ctype.h>
 #include <linux/device.h>
+#include <linux/scatterlist.h>
 #include <linux/usb/quirks.h>
 #include <asm/byteorder.h>
-#include <asm/scatterlist.h>
 
 #include "hcd.h"       /* for usbcore internals */
 #include "usb.h"
@@ -437,13 +437,11 @@ int usb_sg_init (
 #if defined(CONFIG_HIGHMEM) || defined(CONFIG_IOMMU)
                        io->urbs[i]->transfer_buffer = NULL;
 #else
-                       io->urbs[i]->transfer_buffer =
-                               page_address(sg[i].page) + sg[i].offset;
+                       io->urbs[i]->transfer_buffer = sg_virt(&sg[i]);
 #endif
                } else {
                        /* hc may use _only_ transfer_buffer */
-                       io->urbs [i]->transfer_buffer =
-                               page_address (sg [i].page) + sg [i].offset;
+                       io->urbs [i]->transfer_buffer = sg_virt(&sg[i]);
                        len = sg [i].length;
                }
 
index e7d982a..91e999c 100644 (file)
@@ -519,8 +519,7 @@ static void mts_do_sg (struct urb* transfer)
        context->fragment++;
        mts_int_submit_urb(transfer,
                           context->data_pipe,
-                          page_address(sg[context->fragment].page) +
-                          sg[context->fragment].offset,
+                          sg_virt(&sg[context->fragment]),
                           sg[context->fragment].length,
                           context->fragment + 1 == scsi_sg_count(context->srb) ?
                           mts_data_done : mts_do_sg);
@@ -557,7 +556,7 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
                return;
        } else {
                sg = scsi_sglist(srb);
-               desc->context.data = page_address(sg[0].page) + sg[0].offset;
+               desc->context.data = sg_virt(&sg[0]);
                desc->context.data_length = sg[0].length;
        }
 
index e901d31..ea31621 100644 (file)
@@ -360,9 +360,9 @@ static void free_sglist (struct scatterlist *sg, int nents)
        if (!sg)
                return;
        for (i = 0; i < nents; i++) {
-               if (!sg [i].page)
+               if (!sg_page(&sg[i]))
                        continue;
-               kfree (page_address (sg [i].page) + sg [i].offset);
+               kfree (sg_virt(&sg[i]));
        }
        kfree (sg);
 }
index cc8f7c5..889622b 100644 (file)
@@ -195,7 +195,7 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
                 * the *offset and *index values for the next loop. */
                cnt = 0;
                while (cnt < buflen) {
-                       struct page *page = sg->page +
+                       struct page *page = sg_page(sg) +
                                        ((sg->offset + *offset) >> PAGE_SHIFT);
                        unsigned int poff =
                                        (sg->offset + *offset) & (PAGE_SIZE-1);
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
new file mode 100644 (file)
index 0000000..9e33fc4
--- /dev/null
@@ -0,0 +1,8 @@
+# Virtio always gets selected by whoever wants it.
+config VIRTIO
+       bool
+
+# Similarly the virtio ring implementation.
+config VIRTIO_RING
+       bool
+       depends on VIRTIO
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
new file mode 100644 (file)
index 0000000..f70e409
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VIRTIO) += virtio.o
+obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o
diff --git a/drivers/virtio/config.c b/drivers/virtio/config.c
new file mode 100644 (file)
index 0000000..983d482
--- /dev/null
@@ -0,0 +1,13 @@
+/* Configuration space parsing helpers for virtio.
+ *
+ * The configuration is [type][len][... len bytes ...] fields.
+ *
+ * Copyright 2007 Rusty Russell, IBM Corporation.
+ * GPL v2 or later.
+ */
+#include <linux/err.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/bug.h>
+#include <asm/system.h>
+
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
new file mode 100644 (file)
index 0000000..15d7787
--- /dev/null
@@ -0,0 +1,189 @@
+#include <linux/virtio.h>
+#include <linux/spinlock.h>
+#include <linux/virtio_config.h>
+
+static ssize_t device_show(struct device *_d,
+                          struct device_attribute *attr, char *buf)
+{
+       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+       return sprintf(buf, "%hu", dev->id.device);
+}
+static ssize_t vendor_show(struct device *_d,
+                          struct device_attribute *attr, char *buf)
+{
+       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+       return sprintf(buf, "%hu", dev->id.vendor);
+}
+static ssize_t status_show(struct device *_d,
+                          struct device_attribute *attr, char *buf)
+{
+       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+       return sprintf(buf, "0x%08x", dev->config->get_status(dev));
+}
+static ssize_t modalias_show(struct device *_d,
+                            struct device_attribute *attr, char *buf)
+{
+       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+
+       return sprintf(buf, "virtio:d%08Xv%08X\n",
+                      dev->id.device, dev->id.vendor);
+}
+static struct device_attribute virtio_dev_attrs[] = {
+       __ATTR_RO(device),
+       __ATTR_RO(vendor),
+       __ATTR_RO(status),
+       __ATTR_RO(modalias),
+       __ATTR_NULL
+};
+
+static inline int virtio_id_match(const struct virtio_device *dev,
+                                 const struct virtio_device_id *id)
+{
+       if (id->device != dev->id.device)
+               return 0;
+
+       return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor != dev->id.vendor;
+}
+
+/* This looks through all the IDs a driver claims to support.  If any of them
+ * match, we return 1 and the kernel will call virtio_dev_probe(). */
+static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
+{
+       unsigned int i;
+       struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
+       const struct virtio_device_id *ids;
+
+       ids = container_of(_dr, struct virtio_driver, driver)->id_table;
+       for (i = 0; ids[i].device; i++)
+               if (virtio_id_match(dev, &ids[i]))
+                       return 1;
+       return 0;
+}
+
+static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
+{
+       struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
+
+       return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X",
+                             dev->id.device, dev->id.vendor);
+}
+
+static struct bus_type virtio_bus = {
+       .name  = "virtio",
+       .match = virtio_dev_match,
+       .dev_attrs = virtio_dev_attrs,
+       .uevent = virtio_uevent,
+};
+
+static void add_status(struct virtio_device *dev, unsigned status)
+{
+       dev->config->set_status(dev, dev->config->get_status(dev) | status);
+}
+
+static int virtio_dev_probe(struct device *_d)
+{
+       int err;
+       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+       struct virtio_driver *drv = container_of(dev->dev.driver,
+                                                struct virtio_driver, driver);
+
+       add_status(dev, VIRTIO_CONFIG_S_DRIVER);
+       err = drv->probe(dev);
+       if (err)
+               add_status(dev, VIRTIO_CONFIG_S_FAILED);
+       else
+               add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
+       return err;
+}
+
+int register_virtio_driver(struct virtio_driver *driver)
+{
+       driver->driver.bus = &virtio_bus;
+       driver->driver.probe = virtio_dev_probe;
+       return driver_register(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(register_virtio_driver);
+
+void unregister_virtio_driver(struct virtio_driver *driver)
+{
+       driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(unregister_virtio_driver);
+
+int register_virtio_device(struct virtio_device *dev)
+{
+       int err;
+
+       dev->dev.bus = &virtio_bus;
+       sprintf(dev->dev.bus_id, "%u", dev->index);
+
+       /* Acknowledge that we've seen the device. */
+       add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
+
+       /* device_register() causes the bus infrastructure to look for a
+        * matching driver. */
+       err = device_register(&dev->dev);
+       if (err)
+               add_status(dev, VIRTIO_CONFIG_S_FAILED);
+       return err;
+}
+EXPORT_SYMBOL_GPL(register_virtio_device);
+
+void unregister_virtio_device(struct virtio_device *dev)
+{
+       device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(unregister_virtio_device);
+
+int __virtio_config_val(struct virtio_device *vdev,
+                       u8 type, void *val, size_t size)
+{
+       void *token;
+       unsigned int len;
+
+       token = vdev->config->find(vdev, type, &len);
+       if (!token)
+               return -ENOENT;
+
+       if (len != size)
+               return -EIO;
+
+       vdev->config->get(vdev, token, val, size);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__virtio_config_val);
+
+int virtio_use_bit(struct virtio_device *vdev,
+                  void *token, unsigned int len, unsigned int bitnum)
+{
+       unsigned long bits[16];
+
+       /* This makes it convenient to pass-through find() results. */
+       if (!token)
+               return 0;
+
+       /* bit not in range of this bitfield? */
+       if (bitnum * 8 >= len / 2)
+               return 0;
+
+       /* Giant feature bitfields are silly. */
+       BUG_ON(len > sizeof(bits));
+       vdev->config->get(vdev, token, bits, len);
+
+       if (!test_bit(bitnum, bits))
+               return 0;
+
+       /* Set acknowledge bit, and write it back. */
+       set_bit(bitnum + len * 8 / 2, bits);
+       vdev->config->set(vdev, token, bits, len);
+       return 1;
+}
+EXPORT_SYMBOL_GPL(virtio_use_bit);
+
+static int virtio_init(void)
+{
+       if (bus_register(&virtio_bus) != 0)
+               panic("virtio bus registration failed");
+       return 0;
+}
+core_initcall(virtio_init);
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
new file mode 100644 (file)
index 0000000..0e4baca
--- /dev/null
@@ -0,0 +1,313 @@
+/* Virtio ring implementation.
+ *
+ *  Copyright 2007 Rusty Russell IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/virtio.h>
+#include <linux/virtio_ring.h>
+#include <linux/device.h>
+
+#ifdef DEBUG
+/* For development, we want to crash whenever the ring is screwed. */
+#define BAD_RING(vq, fmt...)                   \
+       do { dev_err(&vq->vq.vdev->dev, fmt); BUG(); } while(0)
+#define START_USE(vq) \
+       do { if ((vq)->in_use) panic("in_use = %i\n", (vq)->in_use); (vq)->in_use = __LINE__; mb(); } while(0)
+#define END_USE(vq) \
+       do { BUG_ON(!(vq)->in_use); (vq)->in_use = 0; mb(); } while(0)
+#else
+#define BAD_RING(vq, fmt...)                   \
+       do { dev_err(&vq->vq.vdev->dev, fmt); (vq)->broken = true; } while(0)
+#define START_USE(vq)
+#define END_USE(vq)
+#endif
+
+struct vring_virtqueue
+{
+       struct virtqueue vq;
+
+       /* Actual memory layout for this queue */
+       struct vring vring;
+
+       /* Other side has made a mess, don't try any more. */
+       bool broken;
+
+       /* Number of free buffers */
+       unsigned int num_free;
+       /* Head of free buffer list. */
+       unsigned int free_head;
+       /* Number we've added since last sync. */
+       unsigned int num_added;
+
+       /* Last used index we've seen. */
+       unsigned int last_used_idx;
+
+       /* How to notify other side. FIXME: commonalize hcalls! */
+       void (*notify)(struct virtqueue *vq);
+
+#ifdef DEBUG
+       /* They're supposed to lock for us. */
+       unsigned int in_use;
+#endif
+
+       /* Tokens for callbacks. */
+       void *data[];
+};
+
+#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
+
+static int vring_add_buf(struct virtqueue *_vq,
+                        struct scatterlist sg[],
+                        unsigned int out,
+                        unsigned int in,
+                        void *data)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+       unsigned int i, avail, head, uninitialized_var(prev);
+
+       BUG_ON(data == NULL);
+       BUG_ON(out + in > vq->vring.num);
+       BUG_ON(out + in == 0);
+
+       START_USE(vq);
+
+       if (vq->num_free < out + in) {
+               pr_debug("Can't add buf len %i - avail = %i\n",
+                        out + in, vq->num_free);
+               END_USE(vq);
+               return -ENOSPC;
+       }
+
+       /* We're about to use some buffers from the free list. */
+       vq->num_free -= out + in;
+
+       head = vq->free_head;
+       for (i = vq->free_head; out; i = vq->vring.desc[i].next, out--) {
+               vq->vring.desc[i].flags = VRING_DESC_F_NEXT;
+               vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT)
+                       + sg->offset;
+               vq->vring.desc[i].len = sg->length;
+               prev = i;
+               sg++;
+       }
+       for (; in; i = vq->vring.desc[i].next, in--) {
+               vq->vring.desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
+               vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT)
+                       + sg->offset;
+               vq->vring.desc[i].len = sg->length;
+               prev = i;
+               sg++;
+       }
+       /* Last one doesn't continue. */
+       vq->vring.desc[prev].flags &= ~VRING_DESC_F_NEXT;
+
+       /* Update free pointer */
+       vq->free_head = i;
+
+       /* Set token. */
+       vq->data[head] = data;
+
+       /* Put entry in available array (but don't update avail->idx until they
+        * do sync).  FIXME: avoid modulus here? */
+       avail = (vq->vring.avail->idx + vq->num_added++) % vq->vring.num;
+       vq->vring.avail->ring[avail] = head;
+
+       pr_debug("Added buffer head %i to %p\n", head, vq);
+       END_USE(vq);
+       return 0;
+}
+
+static void vring_kick(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+       START_USE(vq);
+       /* Descriptors and available array need to be set before we expose the
+        * new available array entries. */
+       wmb();
+
+       vq->vring.avail->idx += vq->num_added;
+       vq->num_added = 0;
+
+       /* Need to update avail index before checking if we should notify */
+       mb();
+
+       if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
+               /* Prod other side to tell it about changes. */
+               vq->notify(&vq->vq);
+
+       END_USE(vq);
+}
+
+static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
+{
+       unsigned int i;
+
+       /* Clear data ptr. */
+       vq->data[head] = NULL;
+
+       /* Put back on free list: find end */
+       i = head;
+       while (vq->vring.desc[i].flags & VRING_DESC_F_NEXT) {
+               i = vq->vring.desc[i].next;
+               vq->num_free++;
+       }
+
+       vq->vring.desc[i].next = vq->free_head;
+       vq->free_head = head;
+       /* Plus final descriptor */
+       vq->num_free++;
+}
+
+/* FIXME: We need to tell other side about removal, to synchronize. */
+static void vring_shutdown(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+       unsigned int i;
+
+       for (i = 0; i < vq->vring.num; i++)
+               detach_buf(vq, i);
+}
+
+static inline bool more_used(const struct vring_virtqueue *vq)
+{
+       return vq->last_used_idx != vq->vring.used->idx;
+}
+
+static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+       void *ret;
+       unsigned int i;
+
+       START_USE(vq);
+
+       if (!more_used(vq)) {
+               pr_debug("No more buffers in queue\n");
+               END_USE(vq);
+               return NULL;
+       }
+
+       i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
+       *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
+
+       if (unlikely(i >= vq->vring.num)) {
+               BAD_RING(vq, "id %u out of range\n", i);
+               return NULL;
+       }
+       if (unlikely(!vq->data[i])) {
+               BAD_RING(vq, "id %u is not a head!\n", i);
+               return NULL;
+       }
+
+       /* detach_buf clears data, so grab it now. */
+       ret = vq->data[i];
+       detach_buf(vq, i);
+       vq->last_used_idx++;
+       END_USE(vq);
+       return ret;
+}
+
+static bool vring_restart(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       START_USE(vq);
+       BUG_ON(!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT));
+
+       /* We optimistically turn back on interrupts, then check if there was
+        * more to do. */
+       vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+       mb();
+       if (unlikely(more_used(vq))) {
+               vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+               END_USE(vq);
+               return false;
+       }
+
+       END_USE(vq);
+       return true;
+}
+
+irqreturn_t vring_interrupt(int irq, void *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       if (!more_used(vq)) {
+               pr_debug("virtqueue interrupt with no work for %p\n", vq);
+               return IRQ_NONE;
+       }
+
+       if (unlikely(vq->broken))
+               return IRQ_HANDLED;
+
+       pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
+       if (vq->vq.callback && !vq->vq.callback(&vq->vq))
+               vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+
+       return IRQ_HANDLED;
+}
+
+static struct virtqueue_ops vring_vq_ops = {
+       .add_buf = vring_add_buf,
+       .get_buf = vring_get_buf,
+       .kick = vring_kick,
+       .restart = vring_restart,
+       .shutdown = vring_shutdown,
+};
+
+struct virtqueue *vring_new_virtqueue(unsigned int num,
+                                     struct virtio_device *vdev,
+                                     void *pages,
+                                     void (*notify)(struct virtqueue *),
+                                     bool (*callback)(struct virtqueue *))
+{
+       struct vring_virtqueue *vq;
+       unsigned int i;
+
+       vq = kmalloc(sizeof(*vq) + sizeof(void *)*num, GFP_KERNEL);
+       if (!vq)
+               return NULL;
+
+       vring_init(&vq->vring, num, pages);
+       vq->vq.callback = callback;
+       vq->vq.vdev = vdev;
+       vq->vq.vq_ops = &vring_vq_ops;
+       vq->notify = notify;
+       vq->broken = false;
+       vq->last_used_idx = 0;
+       vq->num_added = 0;
+#ifdef DEBUG
+       vq->in_use = false;
+#endif
+
+       /* No callback?  Tell other side not to bother us. */
+       if (!callback)
+               vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+
+       /* Put everything in free lists. */
+       vq->num_free = num;
+       vq->free_head = 0;
+       for (i = 0; i < num-1; i++)
+               vq->vring.desc[i].next = i+1;
+
+       return &vq->vq;
+}
+
+void vring_del_virtqueue(struct virtqueue *vq)
+{
+       kfree(to_vvq(vq));
+}
+
index 9cfb975..11f6a11 100644 (file)
@@ -175,6 +175,8 @@ static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *ma
        int size;
 
        has_wdt = of_get_property(op->node, "has-wdt", NULL);
+       if (!has_wdt)
+               has_wdt = of_get_property(op->node, "fsl,has-wdt", NULL);
        if (!has_wdt)
                return -ENODEV;
 
@@ -254,6 +256,7 @@ static int mpc5200_wdt_shutdown(struct of_device *op)
 
 static struct of_device_id mpc5200_wdt_match[] = {
        { .compatible = "mpc5200-gpt", },
+       { .compatible = "fsl,mpc5200-gpt", },
        {},
 };
 static struct of_platform_driver mpc5200_wdt_driver = {
index 873802d..756f7e9 100644 (file)
@@ -162,6 +162,7 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
                                if (*e != '\0')
                                        v9ses->uid = ~0;
                        }
+                       kfree(s);
                        break;
 
                default:
index 175b4d9..23581bc 100644 (file)
@@ -687,10 +687,10 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        retval = p9_client_wstat(oldfid, &wstat);
 
 clunk_newdir:
-       p9_client_clunk(olddirfid);
+       p9_client_clunk(newdirfid);
 
 clunk_olddir:
-       p9_client_clunk(newdirfid);
+       p9_client_clunk(olddirfid);
 
 done:
        return retval;
index 76403b1..7249e01 100644 (file)
@@ -2563,7 +2563,7 @@ int nobh_write_end(struct file *file, struct address_space *mapping,
                        struct page *page, void *fsdata)
 {
        struct inode *inode = page->mapping->host;
-       struct buffer_head *head = NULL;
+       struct buffer_head *head = fsdata;
        struct buffer_head *bh;
 
        if (!PageMappedToDisk(page)) {
@@ -2584,7 +2584,6 @@ int nobh_write_end(struct file *file, struct address_space *mapping,
        unlock_page(page);
        page_cache_release(page);
 
-       head = fsdata;
        while (head) {
                bh = head;
                head = head->b_this_page;
index 0a3ee5a..5574ba3 100644 (file)
@@ -103,7 +103,7 @@ extern int cifs_ioctl(struct inode *inode, struct file *filep,
                       unsigned int command, unsigned long arg);
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-extern struct export_operations cifs_export_ops;
+extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
 #define CIFS_VERSION   "1.51"
index d614b91..75949d6 100644 (file)
@@ -53,7 +53,7 @@ static struct dentry *cifs_get_parent(struct dentry *dentry)
        return ERR_PTR(-EACCES);
 }
 
-struct export_operations cifs_export_ops = {
+const struct export_operations cifs_export_ops = {
        .get_parent = cifs_get_parent,
 /*     Following five export operations are unneeded so far and can default:
        .get_dentry =
index 5489b2d..d9ca1e5 100644 (file)
@@ -38,7 +38,7 @@ int sysctl_vfs_cache_pressure __read_mostly = 100;
 EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
 
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock);
-static __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
+__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
 
 EXPORT_SYMBOL(dcache_lock);
 
@@ -1479,6 +1479,8 @@ static void switch_names(struct dentry *dentry, struct dentry *target)
                         * dentry:internal, target:external.  Steal target's
                         * storage and make target internal.
                         */
+                       memcpy(target->d_iname, dentry->d_name.name,
+                                       dentry->d_name.len + 1);
                        dentry->d_name.name = target->d_name.name;
                        target->d_name.name = target->d_iname;
                }
index 11be8a3..6a713b3 100644 (file)
@@ -413,7 +413,7 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
        d_move(old_dentry, dentry);
        fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name,
                old_dentry->d_name.name, S_ISDIR(old_dentry->d_inode->i_mode),
-               NULL, old_dentry->d_inode);
+               NULL, old_dentry);
        fsnotify_oldname_free(old_name);
        unlock_rename(new_dir, old_dir);
        dput(dentry);
index 1ae90ef..0a9882e 100644 (file)
@@ -283,7 +283,7 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
                pg = virt_to_page(addr);
                offset = offset_in_page(addr);
                if (sg) {
-                       sg[i].page = pg;
+                       sg_set_page(&sg[i], pg);
                        sg[i].offset = offset;
                }
                remainder_of_page = PAGE_CACHE_SIZE - offset;
@@ -713,10 +713,13 @@ ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
 {
        struct scatterlist src_sg, dst_sg;
 
-       src_sg.page = src_page;
+       sg_init_table(&src_sg, 1);
+       sg_init_table(&dst_sg, 1);
+
+       sg_set_page(&src_sg, src_page);
        src_sg.offset = src_offset;
        src_sg.length = size;
-       dst_sg.page = dst_page;
+       sg_set_page(&dst_sg, dst_page);
        dst_sg.offset = dst_offset;
        dst_sg.length = size;
        return encrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
@@ -742,10 +745,13 @@ ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
 {
        struct scatterlist src_sg, dst_sg;
 
-       src_sg.page = src_page;
+       sg_init_table(&src_sg, 1);
+       sg_init_table(&dst_sg, 1);
+
+       sg_set_page(&src_sg, src_page);
        src_sg.offset = src_offset;
        src_sg.length = size;
-       dst_sg.page = dst_page;
+       sg_set_page(&dst_sg, dst_page);
        dst_sg.offset = dst_offset;
        dst_sg.length = size;
        return decrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
index 89d9710..263fed8 100644 (file)
@@ -1040,6 +1040,9 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
        };
        int rc = 0;
 
+       sg_init_table(&dst_sg, 1);
+       sg_init_table(&src_sg, 1);
+
        if (unlikely(ecryptfs_verbosity > 0)) {
                ecryptfs_printk(
                        KERN_DEBUG, "Session key encryption key (size [%d]):\n",
index 5276b19..f7f4070 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/string.h>
 #include <linux/efs_fs.h>
 #include <linux/smp_lock.h>
+#include <linux/exportfs.h>
+
 
 static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) {
        struct buffer_head *bh;
@@ -75,13 +77,10 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
        return NULL;
 }
 
-struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp)
+static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino,
+               u32 generation)
 {
-       __u32 *objp = vobjp;
-       unsigned long ino = objp[0];
-       __u32 generation = objp[1];
        struct inode *inode;
-       struct dentry *result;
 
        if (ino == 0)
                return ERR_PTR(-ESTALE);
@@ -91,20 +90,25 @@ struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp)
 
        if (is_bad_inode(inode) ||
            (generation && inode->i_generation != generation)) {
-               result = ERR_PTR(-ESTALE);
-               goto out_iput;
+               iput(inode);
+               return ERR_PTR(-ESTALE);
        }
 
-       result = d_alloc_anon(inode);
-       if (!result) {
-               result = ERR_PTR(-ENOMEM);
-               goto out_iput;
-       }
-       return result;
+       return inode;
+}
 
- out_iput:
-       iput(inode);
-       return result;
+struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   efs_nfs_get_inode);
+}
+
+struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   efs_nfs_get_inode);
 }
 
 struct dentry *efs_get_parent(struct dentry *child)
index 25d0326..c79bc62 100644 (file)
@@ -113,8 +113,9 @@ static const struct super_operations efs_superblock_operations = {
        .remount_fs     = efs_remount,
 };
 
-static struct export_operations efs_export_ops = {
-       .get_dentry     = efs_get_dentry,
+static const struct export_operations efs_export_ops = {
+       .fh_to_dentry   = efs_fh_to_dentry,
+       .fh_to_parent   = efs_fh_to_parent,
        .get_parent     = efs_get_parent,
 };
 
index 8adb32a..109ab5e 100644 (file)
@@ -1,4 +1,13 @@
-
+/*
+ * Copyright (C) Neil Brown 2002
+ * Copyright (C) Christoph Hellwig 2007
+ *
+ * This file contains the code mapping from inodes to NFS file handles,
+ * and for mapping back from file handles to dentries.
+ *
+ * For details on why we do all the strange and hairy things in here
+ * take a look at Documentation/filesystems/Exporting.
+ */
 #include <linux/exportfs.h>
 #include <linux/fs.h>
 #include <linux/file.h>
 #define dprintk(fmt, args...) do{}while(0)
 
 
-static int get_name(struct dentry *dentry, char *name,
+static int get_name(struct vfsmount *mnt, struct dentry *dentry, char *name,
                struct dentry *child);
 
 
-static struct dentry *exportfs_get_dentry(struct super_block *sb, void *obj)
+static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir,
+               char *name, struct dentry *child)
 {
-       struct dentry *result = ERR_PTR(-ESTALE);
-
-       if (sb->s_export_op->get_dentry) {
-               result = sb->s_export_op->get_dentry(sb, obj);
-               if (!result)
-                       result = ERR_PTR(-ESTALE);
-       }
-
-       return result;
-}
-
-static int exportfs_get_name(struct dentry *dir, char *name,
-               struct dentry *child)
-{
-       struct export_operations *nop = dir->d_sb->s_export_op;
+       const struct export_operations *nop = dir->d_sb->s_export_op;
 
        if (nop->get_name)
                return nop->get_name(dir, name, child);
        else
-               return get_name(dir, name, child);
+               return get_name(mnt, dir, name, child);
 }
 
 /*
@@ -98,7 +94,7 @@ find_disconnected_root(struct dentry *dentry)
  * It may already be, as the flag isn't always updated when connection happens.
  */
 static int
-reconnect_path(struct super_block *sb, struct dentry *target_dir)
+reconnect_path(struct vfsmount *mnt, struct dentry *target_dir)
 {
        char nbuf[NAME_MAX+1];
        int noprogress = 0;
@@ -121,7 +117,7 @@ reconnect_path(struct super_block *sb, struct dentry *target_dir)
                        pd->d_flags &= ~DCACHE_DISCONNECTED;
                        spin_unlock(&pd->d_lock);
                        noprogress = 0;
-               } else if (pd == sb->s_root) {
+               } else if (pd == mnt->mnt_sb->s_root) {
                        printk(KERN_ERR "export: Eeek filesystem root is not connected, impossible\n");
                        spin_lock(&pd->d_lock);
                        pd->d_flags &= ~DCACHE_DISCONNECTED;
@@ -147,8 +143,8 @@ reconnect_path(struct super_block *sb, struct dentry *target_dir)
                        struct dentry *npd;
 
                        mutex_lock(&pd->d_inode->i_mutex);
-                       if (sb->s_export_op->get_parent)
-                               ppd = sb->s_export_op->get_parent(pd);
+                       if (mnt->mnt_sb->s_export_op->get_parent)
+                               ppd = mnt->mnt_sb->s_export_op->get_parent(pd);
                        mutex_unlock(&pd->d_inode->i_mutex);
 
                        if (IS_ERR(ppd)) {
@@ -161,7 +157,7 @@ reconnect_path(struct super_block *sb, struct dentry *target_dir)
 
                        dprintk("%s: find name of %lu in %lu\n", __FUNCTION__,
                                pd->d_inode->i_ino, ppd->d_inode->i_ino);
-                       err = exportfs_get_name(ppd, nbuf, pd);
+                       err = exportfs_get_name(mnt, ppd, nbuf, pd);
                        if (err) {
                                dput(ppd);
                                dput(pd);
@@ -214,125 +210,6 @@ reconnect_path(struct super_block *sb, struct dentry *target_dir)
        return 0;
 }
 
-/**
- * find_exported_dentry - helper routine to implement export_operations->decode_fh
- * @sb:                The &super_block identifying the filesystem
- * @obj:       An opaque identifier of the object to be found - passed to
- *             get_inode
- * @parent:    An optional opqaue identifier of the parent of the object.
- * @acceptable:        A function used to test possible &dentries to see if they are
- *             acceptable
- * @context:   A parameter to @acceptable so that it knows on what basis to
- *             judge.
- *
- * find_exported_dentry is the central helper routine to enable file systems
- * to provide the decode_fh() export_operation.  It's main task is to take
- * an &inode, find or create an appropriate &dentry structure, and possibly
- * splice this into the dcache in the correct place.
- *
- * The decode_fh() operation provided by the filesystem should call
- * find_exported_dentry() with the same parameters that it received except
- * that instead of the file handle fragment, pointers to opaque identifiers
- * for the object and optionally its parent are passed.  The default decode_fh
- * routine passes one pointer to the start of the filehandle fragment, and
- * one 8 bytes into the fragment.  It is expected that most filesystems will
- * take this approach, though the offset to the parent identifier may well be
- * different.
- *
- * find_exported_dentry() will call get_dentry to get an dentry pointer from
- * the file system.  If any &dentry in the d_alias list is acceptable, it will
- * be returned.  Otherwise find_exported_dentry() will attempt to splice a new
- * &dentry into the dcache using get_name() and get_parent() to find the
- * appropriate place.
- */
-
-struct dentry *
-find_exported_dentry(struct super_block *sb, void *obj, void *parent,
-                    int (*acceptable)(void *context, struct dentry *de),
-                    void *context)
-{
-       struct dentry *result, *alias;
-       int err = -ESTALE;
-
-       /*
-        * Attempt to find the inode.
-        */
-       result = exportfs_get_dentry(sb, obj);
-       if (IS_ERR(result))
-               return result;
-
-       if (S_ISDIR(result->d_inode->i_mode)) {
-               if (!(result->d_flags & DCACHE_DISCONNECTED)) {
-                       if (acceptable(context, result))
-                               return result;
-                       err = -EACCES;
-                       goto err_result;
-               }
-
-               err = reconnect_path(sb, result);
-               if (err)
-                       goto err_result;
-       } else {
-               struct dentry *target_dir, *nresult;
-               char nbuf[NAME_MAX+1];
-
-               alias = find_acceptable_alias(result, acceptable, context);
-               if (alias)
-                       return alias;
-
-               if (parent == NULL)
-                       goto err_result;
-
-               target_dir = exportfs_get_dentry(sb,parent);
-               if (IS_ERR(target_dir)) {
-                       err = PTR_ERR(target_dir);
-                       goto err_result;
-               }
-
-               err = reconnect_path(sb, target_dir);
-               if (err) {
-                       dput(target_dir);
-                       goto err_result;
-               }
-
-               /*
-                * As we weren't after a directory, have one more step to go.
-                */
-               err = exportfs_get_name(target_dir, nbuf, result);
-               if (!err) {
-                       mutex_lock(&target_dir->d_inode->i_mutex);
-                       nresult = lookup_one_len(nbuf, target_dir,
-                                                strlen(nbuf));
-                       mutex_unlock(&target_dir->d_inode->i_mutex);
-                       if (!IS_ERR(nresult)) {
-                               if (nresult->d_inode) {
-                                       dput(result);
-                                       result = nresult;
-                               } else
-                                       dput(nresult);
-                       }
-               }
-               dput(target_dir);
-       }
-
-       alias = find_acceptable_alias(result, acceptable, context);
-       if (alias)
-               return alias;
-
-       /* drat - I just cannot find anything acceptable */
-       dput(result);
-       /* It might be justifiable to return ESTALE here,
-        * but the filehandle at-least looks reasonable good
-        * and it may just be a permission problem, so returning
-        * -EACCESS is safer
-        */
-       return ERR_PTR(-EACCES);
-
- err_result:
-       dput(result);
-       return ERR_PTR(err);
-}
-
 struct getdents_callback {
        char *name;             /* name that was found. It already points to a
                                   buffer NAME_MAX+1 is size */
@@ -370,8 +247,8 @@ static int filldir_one(void * __buf, const char * name, int len,
  * calls readdir on the parent until it finds an entry with
  * the same inode number as the child, and returns that.
  */
-static int get_name(struct dentry *dentry, char *name,
-                       struct dentry *child)
+static int get_name(struct vfsmount *mnt, struct dentry *dentry,
+               char *name, struct dentry *child)
 {
        struct inode *dir = dentry->d_inode;
        int error;
@@ -387,7 +264,7 @@ static int get_name(struct dentry *dentry, char *name,
        /*
         * Open the directory ...
         */
-       file = dentry_open(dget(dentry), NULL, O_RDONLY);
+       file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY);
        error = PTR_ERR(file);
        if (IS_ERR(file))
                goto out;
@@ -434,100 +311,177 @@ out:
  * can be used to check that it is still valid.  It places them in the
  * filehandle fragment where export_decode_fh expects to find them.
  */
-static int export_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
-                  int connectable)
+static int export_encode_fh(struct dentry *dentry, struct fid *fid,
+               int *max_len, int connectable)
 {
        struct inode * inode = dentry->d_inode;
        int len = *max_len;
-       int type = 1;
+       int type = FILEID_INO32_GEN;
        
        if (len < 2 || (connectable && len < 4))
                return 255;
 
        len = 2;
-       fh[0] = inode->i_ino;
-       fh[1] = inode->i_generation;
+       fid->i32.ino = inode->i_ino;
+       fid->i32.gen = inode->i_generation;
        if (connectable && !S_ISDIR(inode->i_mode)) {
                struct inode *parent;
 
                spin_lock(&dentry->d_lock);
                parent = dentry->d_parent->d_inode;
-               fh[2] = parent->i_ino;
-               fh[3] = parent->i_generation;
+               fid->i32.parent_ino = parent->i_ino;
+               fid->i32.parent_gen = parent->i_generation;
                spin_unlock(&dentry->d_lock);
                len = 4;
-               type = 2;
+               type = FILEID_INO32_GEN_PARENT;
        }
        *max_len = len;
        return type;
 }
 
-
-/**
- * export_decode_fh - default export_operations->decode_fh function
- * @sb:  The superblock
- * @fh:  pointer to the file handle fragment
- * @fh_len: length of file handle fragment
- * @acceptable: function for testing acceptability of dentrys
- * @context:   context for @acceptable
- *
- * This is the default decode_fh() function.
- * a fileid_type of 1 indicates that the filehandlefragment
- * just contains an object identifier understood by  get_dentry.
- * a fileid_type of 2 says that there is also a directory
- * identifier 8 bytes in to the filehandlefragement.
- */
-static struct dentry *export_decode_fh(struct super_block *sb, __u32 *fh, int fh_len,
-                             int fileid_type,
-                        int (*acceptable)(void *context, struct dentry *de),
-                        void *context)
-{
-       __u32 parent[2];
-       parent[0] = parent[1] = 0;
-       if (fh_len < 2 || fileid_type > 2)
-               return NULL;
-       if (fileid_type == 2) {
-               if (fh_len > 2) parent[0] = fh[2];
-               if (fh_len > 3) parent[1] = fh[3];
-       }
-       return find_exported_dentry(sb, fh, parent,
-                                  acceptable, context);
-}
-
-int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
+int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
                int connectable)
 {
-       struct export_operations *nop = dentry->d_sb->s_export_op;
+       const struct export_operations *nop = dentry->d_sb->s_export_op;
        int error;
 
        if (nop->encode_fh)
-               error = nop->encode_fh(dentry, fh, max_len, connectable);
+               error = nop->encode_fh(dentry, fid->raw, max_len, connectable);
        else
-               error = export_encode_fh(dentry, fh, max_len, connectable);
+               error = export_encode_fh(dentry, fid, max_len, connectable);
 
        return error;
 }
 EXPORT_SYMBOL_GPL(exportfs_encode_fh);
 
-struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, int fh_len,
-               int fileid_type, int (*acceptable)(void *, struct dentry *),
-               void *context)
+struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
+               int fh_len, int fileid_type,
+               int (*acceptable)(void *, struct dentry *), void *context)
 {
-       struct export_operations *nop = mnt->mnt_sb->s_export_op;
-       struct dentry *result;
+       const struct export_operations *nop = mnt->mnt_sb->s_export_op;
+       struct dentry *result, *alias;
+       int err;
 
-       if (nop->decode_fh) {
-               result = nop->decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type,
-                       acceptable, context);
+       /*
+        * Try to get any dentry for the given file handle from the filesystem.
+        */
+       result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
+       if (!result)
+               result = ERR_PTR(-ESTALE);
+       if (IS_ERR(result))
+               return result;
+
+       if (S_ISDIR(result->d_inode->i_mode)) {
+               /*
+                * This request is for a directory.
+                *
+                * On the positive side there is only one dentry for each
+                * directory inode.  On the negative side this implies that we
+                * to ensure our dentry is connected all the way up to the
+                * filesystem root.
+                */
+               if (result->d_flags & DCACHE_DISCONNECTED) {
+                       err = reconnect_path(mnt, result);
+                       if (err)
+                               goto err_result;
+               }
+
+               if (!acceptable(context, result)) {
+                       err = -EACCES;
+                       goto err_result;
+               }
+
+               return result;
        } else {
-               result = export_decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type,
-                       acceptable, context);
+               /*
+                * It's not a directory.  Life is a little more complicated.
+                */
+               struct dentry *target_dir, *nresult;
+               char nbuf[NAME_MAX+1];
+
+               /*
+                * See if either the dentry we just got from the filesystem
+                * or any alias for it is acceptable.  This is always true
+                * if this filesystem is exported without the subtreecheck
+                * option.  If the filesystem is exported with the subtree
+                * check option there's a fair chance we need to look at
+                * the parent directory in the file handle and make sure
+                * it's connected to the filesystem root.
+                */
+               alias = find_acceptable_alias(result, acceptable, context);
+               if (alias)
+                       return alias;
+
+               /*
+                * Try to extract a dentry for the parent directory from the
+                * file handle.  If this fails we'll have to give up.
+                */
+               err = -ESTALE;
+               if (!nop->fh_to_parent)
+                       goto err_result;
+
+               target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
+                               fh_len, fileid_type);
+               if (!target_dir)
+                       goto err_result;
+               err = PTR_ERR(target_dir);
+               if (IS_ERR(target_dir))
+                       goto err_result;
+
+               /*
+                * And as usual we need to make sure the parent directory is
+                * connected to the filesystem root.  The VFS really doesn't
+                * like disconnected directories..
+                */
+               err = reconnect_path(mnt, target_dir);
+               if (err) {
+                       dput(target_dir);
+                       goto err_result;
+               }
+
+               /*
+                * Now that we've got both a well-connected parent and a
+                * dentry for the inode we're after, make sure that our
+                * inode is actually connected to the parent.
+                */
+               err = exportfs_get_name(mnt, target_dir, nbuf, result);
+               if (!err) {
+                       mutex_lock(&target_dir->d_inode->i_mutex);
+                       nresult = lookup_one_len(nbuf, target_dir,
+                                                strlen(nbuf));
+                       mutex_unlock(&target_dir->d_inode->i_mutex);
+                       if (!IS_ERR(nresult)) {
+                               if (nresult->d_inode) {
+                                       dput(result);
+                                       result = nresult;
+                               } else
+                                       dput(nresult);
+                       }
+               }
+
+               /*
+                * At this point we are done with the parent, but it's pinned
+                * by the child dentry anyway.
+                */
+               dput(target_dir);
+
+               /*
+                * And finally make sure the dentry is actually acceptable
+                * to NFSD.
+                */
+               alias = find_acceptable_alias(result, acceptable, context);
+               if (!alias) {
+                       err = -EACCES;
+                       goto err_result;
+               }
+
+               return alias;
        }
 
-       return result;
+ err_result:
+       dput(result);
+       return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(exportfs_decode_fh);
 
-EXPORT_SYMBOL(find_exported_dentry);
-
 MODULE_LICENSE("GPL");
index 05d9342..d868e26 100644 (file)
 
 typedef struct ext2_dir_entry_2 ext2_dirent;
 
+static inline unsigned ext2_rec_len_from_disk(__le16 dlen)
+{
+       unsigned len = le16_to_cpu(dlen);
+
+       if (len == EXT2_MAX_REC_LEN)
+               return 1 << 16;
+       return len;
+}
+
+static inline __le16 ext2_rec_len_to_disk(unsigned len)
+{
+       if (len == (1 << 16))
+               return cpu_to_le16(EXT2_MAX_REC_LEN);
+       else if (len > (1 << 16))
+               BUG();
+       return cpu_to_le16(len);
+}
+
 /*
  * ext2 uses block-sized chunks. Arguably, sector-sized ones would be
  * more robust, but we have what we have
@@ -106,7 +124,7 @@ static void ext2_check_page(struct page *page)
        }
        for (offs = 0; offs <= limit - EXT2_DIR_REC_LEN(1); offs += rec_len) {
                p = (ext2_dirent *)(kaddr + offs);
-               rec_len = le16_to_cpu(p->rec_len);
+               rec_len = ext2_rec_len_from_disk(p->rec_len);
 
                if (rec_len < EXT2_DIR_REC_LEN(1))
                        goto Eshort;
@@ -204,7 +222,8 @@ static inline int ext2_match (int len, const char * const name,
  */
 static inline ext2_dirent *ext2_next_entry(ext2_dirent *p)
 {
-       return (ext2_dirent *)((char*)p + le16_to_cpu(p->rec_len));
+       return (ext2_dirent *)((char *)p +
+                       ext2_rec_len_from_disk(p->rec_len));
 }
 
 static inline unsigned 
@@ -316,7 +335,7 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
                                        return 0;
                                }
                        }
-                       filp->f_pos += le16_to_cpu(de->rec_len);
+                       filp->f_pos += ext2_rec_len_from_disk(de->rec_len);
                }
                ext2_put_page(page);
        }
@@ -425,7 +444,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
 {
        loff_t pos = page_offset(page) +
                        (char *) de - (char *) page_address(page);
-       unsigned len = le16_to_cpu(de->rec_len);
+       unsigned len = ext2_rec_len_from_disk(de->rec_len);
        int err;
 
        lock_page(page);
@@ -482,7 +501,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
                                /* We hit i_size */
                                name_len = 0;
                                rec_len = chunk_size;
-                               de->rec_len = cpu_to_le16(chunk_size);
+                               de->rec_len = ext2_rec_len_to_disk(chunk_size);
                                de->inode = 0;
                                goto got_it;
                        }
@@ -496,7 +515,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
                        if (ext2_match (namelen, name, de))
                                goto out_unlock;
                        name_len = EXT2_DIR_REC_LEN(de->name_len);
-                       rec_len = le16_to_cpu(de->rec_len);
+                       rec_len = ext2_rec_len_from_disk(de->rec_len);
                        if (!de->inode && rec_len >= reclen)
                                goto got_it;
                        if (rec_len >= name_len + reclen)
@@ -518,8 +537,8 @@ got_it:
                goto out_unlock;
        if (de->inode) {
                ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len);
-               de1->rec_len = cpu_to_le16(rec_len - name_len);
-               de->rec_len = cpu_to_le16(name_len);
+               de1->rec_len = ext2_rec_len_to_disk(rec_len - name_len);
+               de->rec_len = ext2_rec_len_to_disk(name_len);
                de = de1;
        }
        de->name_len = namelen;
@@ -550,7 +569,8 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
        struct inode *inode = mapping->host;
        char *kaddr = page_address(page);
        unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
-       unsigned to = ((char*)dir - kaddr) + le16_to_cpu(dir->rec_len);
+       unsigned to = ((char *)dir - kaddr) +
+                               ext2_rec_len_from_disk(dir->rec_len);
        loff_t pos;
        ext2_dirent * pde = NULL;
        ext2_dirent * de = (ext2_dirent *) (kaddr + from);
@@ -574,7 +594,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
                                                        &page, NULL);
        BUG_ON(err);
        if (pde)
-               pde->rec_len = cpu_to_le16(to - from);
+               pde->rec_len = ext2_rec_len_to_disk(to - from);
        dir->inode = 0;
        err = ext2_commit_chunk(page, pos, to - from);
        inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
@@ -610,14 +630,14 @@ int ext2_make_empty(struct inode *inode, struct inode *parent)
        memset(kaddr, 0, chunk_size);
        de = (struct ext2_dir_entry_2 *)kaddr;
        de->name_len = 1;
-       de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(1));
+       de->rec_len = ext2_rec_len_to_disk(EXT2_DIR_REC_LEN(1));
        memcpy (de->name, ".\0\0", 4);
        de->inode = cpu_to_le32(inode->i_ino);
        ext2_set_de_type (de, inode);
 
        de = (struct ext2_dir_entry_2 *)(kaddr + EXT2_DIR_REC_LEN(1));
        de->name_len = 2;
-       de->rec_len = cpu_to_le16(chunk_size - EXT2_DIR_REC_LEN(1));
+       de->rec_len = ext2_rec_len_to_disk(chunk_size - EXT2_DIR_REC_LEN(1));
        de->inode = cpu_to_le32(parent->i_ino);
        memcpy (de->name, "..\0", 4);
        ext2_set_de_type (de, inode);
index 77bd5f9..154e25f 100644 (file)
@@ -311,13 +311,10 @@ static const struct super_operations ext2_sops = {
 #endif
 };
 
-static struct dentry *ext2_get_dentry(struct super_block *sb, void *vobjp)
+static struct inode *ext2_nfs_get_inode(struct super_block *sb,
+               u64 ino, u32 generation)
 {
-       __u32 *objp = vobjp;
-       unsigned long ino = objp[0];
-       __u32 generation = objp[1];
        struct inode *inode;
-       struct dentry *result;
 
        if (ino < EXT2_FIRST_INO(sb) && ino != EXT2_ROOT_INO)
                return ERR_PTR(-ESTALE);
@@ -338,15 +335,21 @@ static struct dentry *ext2_get_dentry(struct super_block *sb, void *vobjp)
                iput(inode);
                return ERR_PTR(-ESTALE);
        }
-       /* now to find a dentry.
-        * If possible, get a well-connected one
-        */
-       result = d_alloc_anon(inode);
-       if (!result) {
-               iput(inode);
-               return ERR_PTR(-ENOMEM);
-       }
-       return result;
+       return inode;
+}
+
+static struct dentry *ext2_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   ext2_nfs_get_inode);
+}
+
+static struct dentry *ext2_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   ext2_nfs_get_inode);
 }
 
 /* Yes, most of these are left as NULL!!
@@ -354,9 +357,10 @@ static struct dentry *ext2_get_dentry(struct super_block *sb, void *vobjp)
  * systems, but can be improved upon.
  * Currently only get_parent is required.
  */
-static struct export_operations ext2_export_ops = {
+static const struct export_operations ext2_export_ops = {
+       .fh_to_dentry = ext2_fh_to_dentry,
+       .fh_to_parent = ext2_fh_to_parent,
        .get_parent = ext2_get_parent,
-       .get_dentry = ext2_get_dentry,
 };
 
 static unsigned long get_sb_block(void **data)
index 81868c0..de55da9 100644 (file)
@@ -631,13 +631,10 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
 }
 
 
-static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp)
+static struct inode *ext3_nfs_get_inode(struct super_block *sb,
+               u64 ino, u32 generation)
 {
-       __u32 *objp = vobjp;
-       unsigned long ino = objp[0];
-       __u32 generation = objp[1];
        struct inode *inode;
-       struct dentry *result;
 
        if (ino < EXT3_FIRST_INO(sb) && ino != EXT3_ROOT_INO)
                return ERR_PTR(-ESTALE);
@@ -660,15 +657,22 @@ static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp)
                iput(inode);
                return ERR_PTR(-ESTALE);
        }
-       /* now to find a dentry.
-        * If possible, get a well-connected one
-        */
-       result = d_alloc_anon(inode);
-       if (!result) {
-               iput(inode);
-               return ERR_PTR(-ENOMEM);
-       }
-       return result;
+
+       return inode;
+}
+
+static struct dentry *ext3_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   ext3_nfs_get_inode);
+}
+
+static struct dentry *ext3_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   ext3_nfs_get_inode);
 }
 
 #ifdef CONFIG_QUOTA
@@ -737,9 +741,10 @@ static const struct super_operations ext3_sops = {
 #endif
 };
 
-static struct export_operations ext3_export_ops = {
+static const struct export_operations ext3_export_ops = {
+       .fh_to_dentry = ext3_fh_to_dentry,
+       .fh_to_parent = ext3_fh_to_parent,
        .get_parent = ext3_get_parent,
-       .get_dentry = ext3_get_dentry,
 };
 
 enum {
index b11e9e2..8031dc0 100644 (file)
@@ -686,13 +686,10 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
 }
 
 
-static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp)
+static struct inode *ext4_nfs_get_inode(struct super_block *sb,
+               u64 ino, u32 generation)
 {
-       __u32 *objp = vobjp;
-       unsigned long ino = objp[0];
-       __u32 generation = objp[1];
        struct inode *inode;
-       struct dentry *result;
 
        if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)
                return ERR_PTR(-ESTALE);
@@ -715,15 +712,22 @@ static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp)
                iput(inode);
                return ERR_PTR(-ESTALE);
        }
-       /* now to find a dentry.
-        * If possible, get a well-connected one
-        */
-       result = d_alloc_anon(inode);
-       if (!result) {
-               iput(inode);
-               return ERR_PTR(-ENOMEM);
-       }
-       return result;
+
+       return inode;
+}
+
+static struct dentry *ext4_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   ext4_nfs_get_inode);
+}
+
+static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   ext4_nfs_get_inode);
 }
 
 #ifdef CONFIG_QUOTA
@@ -792,9 +796,10 @@ static const struct super_operations ext4_sops = {
 #endif
 };
 
-static struct export_operations ext4_export_ops = {
+static const struct export_operations ext4_export_ops = {
+       .fh_to_dentry = ext4_fh_to_dentry,
+       .fh_to_parent = ext4_fh_to_parent,
        .get_parent = ext4_get_parent,
-       .get_dentry = ext4_get_dentry,
 };
 
 enum {
index c0c5e9c..920a576 100644 (file)
@@ -653,24 +653,15 @@ static const struct super_operations fat_sops = {
  * of i_logstart is used to store the directory entry offset.
  */
 
-static struct dentry *
-fat_decode_fh(struct super_block *sb, __u32 *fh, int len, int fhtype,
-             int (*acceptable)(void *context, struct dentry *de),
-             void *context)
-{
-       if (fhtype != 3)
-               return ERR_PTR(-ESTALE);
-       if (len < 5)
-               return ERR_PTR(-ESTALE);
-
-       return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, context);
-}
-
-static struct dentry *fat_get_dentry(struct super_block *sb, void *inump)
+static struct dentry *fat_fh_to_dentry(struct super_block *sb,
+               struct fid *fid, int fh_len, int fh_type)
 {
        struct inode *inode = NULL;
        struct dentry *result;
-       __u32 *fh = inump;
+       u32 *fh = fid->raw;
+
+       if (fh_len < 5 || fh_type != 3)
+               return NULL;
 
        inode = iget(sb, fh[0]);
        if (!inode || is_bad_inode(inode) || inode->i_generation != fh[1]) {
@@ -783,10 +774,9 @@ out:
        return parent;
 }
 
-static struct export_operations fat_export_ops = {
-       .decode_fh      = fat_decode_fh,
+static const struct export_operations fat_export_ops = {
        .encode_fh      = fat_encode_fh,
-       .get_dentry     = fat_get_dentry,
+       .fh_to_dentry   = fat_fh_to_dentry,
        .get_parent     = fat_get_parent,
 };
 
index e2d1347..b9da623 100644 (file)
 #define GFS2_LARGE_FH_SIZE 8
 #define GFS2_OLD_FH_SIZE 10
 
-static struct dentry *gfs2_decode_fh(struct super_block *sb,
-                                    __u32 *p,
-                                    int fh_len,
-                                    int fh_type,
-                                    int (*acceptable)(void *context,
-                                                      struct dentry *dentry),
-                                    void *context)
-{
-       __be32 *fh = (__force __be32 *)p;
-       struct gfs2_inum_host inum, parent;
-
-       memset(&parent, 0, sizeof(struct gfs2_inum));
-
-       switch (fh_len) {
-       case GFS2_LARGE_FH_SIZE:
-       case GFS2_OLD_FH_SIZE:
-               parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
-               parent.no_formal_ino |= be32_to_cpu(fh[5]);
-               parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
-               parent.no_addr |= be32_to_cpu(fh[7]);
-       case GFS2_SMALL_FH_SIZE:
-               inum.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
-               inum.no_formal_ino |= be32_to_cpu(fh[1]);
-               inum.no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
-               inum.no_addr |= be32_to_cpu(fh[3]);
-               break;
-       default:
-               return NULL;
-       }
-
-       return gfs2_export_ops.find_exported_dentry(sb, &inum, &parent,
-                                                   acceptable, context);
-}
-
 static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
                          int connectable)
 {
@@ -189,10 +155,10 @@ static struct dentry *gfs2_get_parent(struct dentry *child)
        return dentry;
 }
 
-static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj)
+static struct dentry *gfs2_get_dentry(struct super_block *sb,
+               struct gfs2_inum_host *inum)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
-       struct gfs2_inum_host *inum = inum_obj;
        struct gfs2_holder i_gh, ri_gh, rgd_gh;
        struct gfs2_rgrpd *rgd;
        struct inode *inode;
@@ -289,11 +255,50 @@ fail:
        return ERR_PTR(error);
 }
 
-struct export_operations gfs2_export_ops = {
-       .decode_fh = gfs2_decode_fh,
+static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       struct gfs2_inum_host this;
+       __be32 *fh = (__force __be32 *)fid->raw;
+
+       switch (fh_type) {
+       case GFS2_SMALL_FH_SIZE:
+       case GFS2_LARGE_FH_SIZE:
+       case GFS2_OLD_FH_SIZE:
+               this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
+               this.no_formal_ino |= be32_to_cpu(fh[1]);
+               this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
+               this.no_addr |= be32_to_cpu(fh[3]);
+               return gfs2_get_dentry(sb, &this);
+       default:
+               return NULL;
+       }
+}
+
+static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       struct gfs2_inum_host parent;
+       __be32 *fh = (__force __be32 *)fid->raw;
+
+       switch (fh_type) {
+       case GFS2_LARGE_FH_SIZE:
+       case GFS2_OLD_FH_SIZE:
+               parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
+               parent.no_formal_ino |= be32_to_cpu(fh[5]);
+               parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
+               parent.no_addr |= be32_to_cpu(fh[7]);
+               return gfs2_get_dentry(sb, &parent);
+       default:
+               return NULL;
+       }
+}
+
+const struct export_operations gfs2_export_ops = {
        .encode_fh = gfs2_encode_fh,
+       .fh_to_dentry = gfs2_fh_to_dentry,
+       .fh_to_parent = gfs2_fh_to_parent,
        .get_name = gfs2_get_name,
        .get_parent = gfs2_get_parent,
-       .get_dentry = gfs2_get_dentry,
 };
 
index 407029b..da84905 100644 (file)
@@ -14,6 +14,6 @@
 
 extern struct file_system_type gfs2_fs_type;
 extern struct file_system_type gfs2meta_fs_type;
-extern struct export_operations gfs2_export_ops;
+extern const struct export_operations gfs2_export_ops;
 
 #endif /* __OPS_FSTYPE_DOT_H__ */
index 7457501..2c5b921 100644 (file)
@@ -666,6 +666,49 @@ out:
 }
 EXPORT_SYMBOL_GPL(inotify_add_watch);
 
+/**
+ * inotify_clone_watch - put the watch next to existing one
+ * @old: already installed watch
+ * @new: new watch
+ *
+ * Caller must hold the inotify_mutex of inode we are dealing with;
+ * it is expected to remove the old watch before unlocking the inode.
+ */
+s32 inotify_clone_watch(struct inotify_watch *old, struct inotify_watch *new)
+{
+       struct inotify_handle *ih = old->ih;
+       int ret = 0;
+
+       new->mask = old->mask;
+       new->ih = ih;
+
+       mutex_lock(&ih->mutex);
+
+       /* Initialize a new watch */
+       ret = inotify_handle_get_wd(ih, new);
+       if (unlikely(ret))
+               goto out;
+       ret = new->wd;
+
+       get_inotify_handle(ih);
+
+       new->inode = igrab(old->inode);
+
+       list_add(&new->h_list, &ih->watches);
+       list_add(&new->i_list, &old->inode->inotify_watches);
+out:
+       mutex_unlock(&ih->mutex);
+       return ret;
+}
+
+void inotify_evict_watch(struct inotify_watch *watch)
+{
+       get_inotify_watch(watch);
+       mutex_lock(&watch->ih->mutex);
+       inotify_remove_watch_locked(watch->ih, watch);
+       mutex_unlock(&watch->ih->mutex);
+}
+
 /**
  * inotify_rm_wd - remove a watch from an inotify instance
  * @ih: inotify handle
index 4af856a..29f9753 100644 (file)
@@ -42,16 +42,6 @@ isofs_export_iget(struct super_block *sb,
        return result;
 }
 
-static struct dentry *
-isofs_export_get_dentry(struct super_block *sb, void *vobjp)
-{
-       __u32 *objp = vobjp;
-       unsigned long block = objp[0];
-       unsigned long offset = objp[1];
-       __u32 generation = objp[2];
-       return isofs_export_iget(sb, block, offset, generation);
-}
-
 /* This function is surprisingly simple.  The trick is understanding
  * that "child" is always a directory. So, to find its parent, you
  * simply need to find its ".." entry, normalize its block and offset,
@@ -182,43 +172,44 @@ isofs_export_encode_fh(struct dentry *dentry,
        return type;
 }
 
+struct isofs_fid {
+       u32 block;
+       u16 offset;
+       u16 parent_offset;
+       u32 generation;
+       u32 parent_block;
+       u32 parent_generation;
+};
 
-static struct dentry *
-isofs_export_decode_fh(struct super_block *sb,
-                      __u32 *fh32,
-                      int fh_len,
-                      int fileid_type,
-                      int (*acceptable)(void *context, struct dentry *de),
-                      void *context)
+static struct dentry *isofs_fh_to_dentry(struct super_block *sb,
+       struct fid *fid, int fh_len, int fh_type)
 {
-       __u16 *fh16 = (__u16*)fh32;
-       __u32 child[3];   /* The child is what triggered all this. */
-       __u32 parent[3];  /* The parent is just along for the ride. */
+       struct isofs_fid *ifid = (struct isofs_fid *)fid;
 
-       if (fh_len < 3 || fileid_type > 2)
+       if (fh_len < 3 || fh_type > 2)
                return NULL;
 
-       child[0] = fh32[0];
-       child[1] = fh16[2];  /* fh16 [sic] */
-       child[2] = fh32[2];
-
-       parent[0] = 0;
-       parent[1] = 0;
-       parent[2] = 0;
-       if (fileid_type == 2) {
-               if (fh_len > 2) parent[0] = fh32[3];
-               parent[1] = fh16[3];  /* fh16 [sic] */
-               if (fh_len > 4) parent[2] = fh32[4];
-       }
-
-       return sb->s_export_op->find_exported_dentry(sb, child, parent,
-                                                    acceptable, context);
+       return isofs_export_iget(sb, ifid->block, ifid->offset,
+                       ifid->generation);
 }
 
+static struct dentry *isofs_fh_to_parent(struct super_block *sb,
+               struct fid *fid, int fh_len, int fh_type)
+{
+       struct isofs_fid *ifid = (struct isofs_fid *)fid;
+
+       if (fh_type != 2)
+               return NULL;
+
+       return isofs_export_iget(sb,
+                       fh_len > 2 ? ifid->parent_block : 0,
+                       ifid->parent_offset,
+                       fh_len > 4 ? ifid->parent_generation : 0);
+}
 
-struct export_operations isofs_export_ops = {
-       .decode_fh      = isofs_export_decode_fh,
+const struct export_operations isofs_export_ops = {
        .encode_fh      = isofs_export_encode_fh,
-       .get_dentry     = isofs_export_get_dentry,
+       .fh_to_dentry   = isofs_fh_to_dentry,
+       .fh_to_parent   = isofs_fh_to_parent,
        .get_parent     = isofs_export_get_parent,
 };
index a07e67b..f3213f9 100644 (file)
@@ -178,4 +178,4 @@ isofs_normalize_block_and_offset(struct iso_directory_record* de,
 extern const struct inode_operations isofs_dir_inode_operations;
 extern const struct file_operations isofs_dir_operations;
 extern const struct address_space_operations isofs_symlink_aops;
-extern struct export_operations isofs_export_ops;
+extern const struct export_operations isofs_export_ops;
index 8ec9323..9728614 100644 (file)
@@ -228,11 +228,28 @@ struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
        return acl;
 }
 
+static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *acl)
+{
+       char *value = NULL;
+       size_t size = 0;
+       int rc;
+
+       if (acl) {
+               value = jffs2_acl_to_medium(acl, &size);
+               if (IS_ERR(value))
+                       return PTR_ERR(value);
+       }
+       rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
+       if (!value && rc == -ENODATA)
+               rc = 0;
+       kfree(value);
+
+       return rc;
+}
+
 static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 {
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-       size_t size = 0;
-       char *value = NULL;
        int rc, xprefix;
 
        if (S_ISLNK(inode->i_mode))
@@ -267,17 +284,7 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        default:
                return -EINVAL;
        }
-       if (acl) {
-               value = jffs2_acl_to_medium(acl, &size);
-               if (IS_ERR(value))
-                       return PTR_ERR(value);
-       }
-
-       rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
-       if (!value && rc == -ENODATA)
-               rc = 0;
-       if (value)
-               kfree(value);
+       rc = __jffs2_set_acl(inode, xprefix, acl);
        if (!rc) {
                switch(type) {
                case ACL_TYPE_ACCESS:
@@ -312,37 +319,59 @@ int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd)
        return generic_permission(inode, mask, jffs2_check_acl);
 }
 
-int jffs2_init_acl(struct inode *inode, struct posix_acl *acl)
+int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode)
 {
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-       struct posix_acl *clone;
-       mode_t mode;
-       int rc = 0;
+       struct posix_acl *acl, *clone;
+       int rc;
 
-       f->i_acl_access = JFFS2_ACL_NOT_CACHED;
-       f->i_acl_default = JFFS2_ACL_NOT_CACHED;
+       f->i_acl_default = NULL;
+       f->i_acl_access = NULL;
+
+       if (S_ISLNK(*i_mode))
+               return 0;       /* Symlink always has no-ACL */
+
+       acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+
+       if (!acl) {
+               *i_mode &= ~current->fs->umask;
+       } else {
+               if (S_ISDIR(*i_mode))
+                       jffs2_iset_acl(inode, &f->i_acl_default, acl);
 
-       if (acl) {
-               if (S_ISDIR(inode->i_mode)) {
-                       rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
-                       if (rc)
-                               goto cleanup;
-               }
                clone = posix_acl_clone(acl, GFP_KERNEL);
-               rc = -ENOMEM;
                if (!clone)
-                       goto cleanup;
-               mode = inode->i_mode;
-               rc = posix_acl_create_masq(clone, &mode);
-               if (rc >= 0) {
-                       inode->i_mode = mode;
-                       if (rc > 0)
-                               rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone);
-               }
+                       return -ENOMEM;
+               rc = posix_acl_create_masq(clone, (mode_t *)i_mode);
+               if (rc < 0)
+                       return rc;
+               if (rc > 0)
+                       jffs2_iset_acl(inode, &f->i_acl_access, clone);
+
                posix_acl_release(clone);
        }
- cleanup:
-       posix_acl_release(acl);
+       return 0;
+}
+
+int jffs2_init_acl_post(struct inode *inode)
+{
+       struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+       int rc;
+
+       if (f->i_acl_default) {
+               rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, f->i_acl_default);
+               if (rc)
+                       return rc;
+       }
+
+       if (f->i_acl_access) {
+               rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, f->i_acl_access);
+               if (rc)
+                       return rc;
+       }
+
        return rc;
 }
 
index 90a2dbf..76c6ebd 100644 (file)
@@ -31,7 +31,8 @@ struct jffs2_acl_header {
 extern struct posix_acl *jffs2_get_acl(struct inode *inode, int type);
 extern int jffs2_permission(struct inode *, int, struct nameidata *);
 extern int jffs2_acl_chmod(struct inode *);
-extern int jffs2_init_acl(struct inode *, struct posix_acl *);
+extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *);
+extern int jffs2_init_acl_post(struct inode *);
 extern void jffs2_clear_acl(struct jffs2_inode_info *);
 
 extern struct xattr_handler jffs2_acl_access_xattr_handler;
@@ -39,10 +40,11 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler;
 
 #else
 
-#define jffs2_get_acl(inode, type)     (NULL)
-#define jffs2_permission NULL
-#define jffs2_acl_chmod(inode)         (0)
-#define jffs2_init_acl(inode,dir)      (0)
+#define jffs2_get_acl(inode, type)             (NULL)
+#define jffs2_permission                       (NULL)
+#define jffs2_acl_chmod(inode)                 (0)
+#define jffs2_init_acl_pre(dir_i,inode,mode)   (0)
+#define jffs2_init_acl_post(inode)             (0)
 #define jffs2_clear_acl(f)
 
 #endif /* CONFIG_JFFS2_FS_POSIX_ACL */
index 8353eb9..787e392 100644 (file)
@@ -182,7 +182,6 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
        struct jffs2_inode_info *f, *dir_f;
        struct jffs2_sb_info *c;
        struct inode *inode;
-       struct posix_acl *acl;
        int ret;
 
        ri = jffs2_alloc_raw_inode();
@@ -193,7 +192,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
 
        D1(printk(KERN_DEBUG "jffs2_create()\n"));
 
-       inode = jffs2_new_inode(dir_i, mode, ri, &acl);
+       inode = jffs2_new_inode(dir_i, mode, ri);
 
        if (IS_ERR(inode)) {
                D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n"));
@@ -211,14 +210,6 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
 
        ret = jffs2_do_create(c, dir_f, f, ri,
                              dentry->d_name.name, dentry->d_name.len);
-
-       if (ret)
-               goto fail_acl;
-
-       ret = jffs2_init_security(inode, dir_i);
-       if (ret)
-               goto fail_acl;
-       ret = jffs2_init_acl(inode, acl);
        if (ret)
                goto fail;
 
@@ -231,8 +222,6 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
                  inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
        return 0;
 
- fail_acl:
-       posix_acl_release(acl);
  fail:
        make_bad_inode(inode);
        iput(inode);
@@ -309,7 +298,6 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        struct jffs2_full_dirent *fd;
        int namelen;
        uint32_t alloclen;
-       struct posix_acl *acl;
        int ret, targetlen = strlen(target);
 
        /* FIXME: If you care. We'd need to use frags for the target
@@ -336,7 +324,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                return ret;
        }
 
-       inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri, &acl);
+       inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri);
 
        if (IS_ERR(inode)) {
                jffs2_free_raw_inode(ri);
@@ -366,7 +354,6 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                up(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
-               posix_acl_release(acl);
                return PTR_ERR(fn);
        }
 
@@ -377,7 +364,6 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                up(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
-               posix_acl_release(acl);
                return -ENOMEM;
        }
 
@@ -395,10 +381,9 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        ret = jffs2_init_security(inode, dir_i);
        if (ret) {
                jffs2_clear_inode(inode);
-               posix_acl_release(acl);
                return ret;
        }
-       ret = jffs2_init_acl(inode, acl);
+       ret = jffs2_init_acl_post(inode);
        if (ret) {
                jffs2_clear_inode(inode);
                return ret;
@@ -476,7 +461,6 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
        struct jffs2_full_dirent *fd;
        int namelen;
        uint32_t alloclen;
-       struct posix_acl *acl;
        int ret;
 
        mode |= S_IFDIR;
@@ -499,7 +483,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
                return ret;
        }
 
-       inode = jffs2_new_inode(dir_i, mode, ri, &acl);
+       inode = jffs2_new_inode(dir_i, mode, ri);
 
        if (IS_ERR(inode)) {
                jffs2_free_raw_inode(ri);
@@ -526,7 +510,6 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
                up(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
-               posix_acl_release(acl);
                return PTR_ERR(fn);
        }
        /* No data here. Only a metadata node, which will be
@@ -540,10 +523,9 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
        ret = jffs2_init_security(inode, dir_i);
        if (ret) {
                jffs2_clear_inode(inode);
-               posix_acl_release(acl);
                return ret;
        }
-       ret = jffs2_init_acl(inode, acl);
+       ret = jffs2_init_acl_post(inode);
        if (ret) {
                jffs2_clear_inode(inode);
                return ret;
@@ -639,7 +621,6 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
        union jffs2_device_node dev;
        int devlen = 0;
        uint32_t alloclen;
-       struct posix_acl *acl;
        int ret;
 
        if (!new_valid_dev(rdev))
@@ -666,7 +647,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
                return ret;
        }
 
-       inode = jffs2_new_inode(dir_i, mode, ri, &acl);
+       inode = jffs2_new_inode(dir_i, mode, ri);
 
        if (IS_ERR(inode)) {
                jffs2_free_raw_inode(ri);
@@ -695,7 +676,6 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
                up(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
-               posix_acl_release(acl);
                return PTR_ERR(fn);
        }
        /* No data here. Only a metadata node, which will be
@@ -709,10 +689,9 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
        ret = jffs2_init_security(inode, dir_i);
        if (ret) {
                jffs2_clear_inode(inode);
-               posix_acl_release(acl);
                return ret;
        }
-       ret = jffs2_init_acl(inode, acl);
+       ret = jffs2_init_acl_post(inode);
        if (ret) {
                jffs2_clear_inode(inode);
                return ret;
index 023a175..f9c5dd6 100644 (file)
@@ -255,7 +255,7 @@ static int jffs2_write_end(struct file *filp, struct address_space *mapping,
                   _whole_ page. This helps to reduce the number of
                   nodes in files which have many short writes, like
                   syslog files. */
-               start = aligned_start = 0;
+               aligned_start = 0;
        }
 
        ri = jffs2_alloc_raw_inode();
@@ -291,14 +291,11 @@ static int jffs2_write_end(struct file *filp, struct address_space *mapping,
        }
 
        /* Adjust writtenlen for the padding we did, so we don't confuse our caller */
-       if (writtenlen < (start&3))
-               writtenlen = 0;
-       else
-               writtenlen -= (start&3);
+       writtenlen -= min(writtenlen, (start - aligned_start));
 
        if (writtenlen) {
-               if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) {
-                       inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen;
+               if (inode->i_size < pos + writtenlen) {
+                       inode->i_size = pos + writtenlen;
                        inode->i_blocks = (inode->i_size + 511) >> 9;
 
                        inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime));
index ed85f9a..d2e06f7 100644 (file)
@@ -402,8 +402,7 @@ void jffs2_write_super (struct super_block *sb)
 
 /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
    fill in the raw_inode while you're at it. */
-struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri,
-                              struct posix_acl **acl)
+struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
 {
        struct inode *inode;
        struct super_block *sb = dir_i->i_sb;
@@ -438,19 +437,11 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
 
        /* POSIX ACLs have to be processed now, at least partly.
           The umask is only applied if there's no default ACL */
-       if (!S_ISLNK(mode)) {
-               *acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT);
-               if (IS_ERR(*acl)) {
-                       make_bad_inode(inode);
-                       iput(inode);
-                       inode = (void *)*acl;
-                       *acl = NULL;
-                       return inode;
-               }
-               if (!(*acl))
-                       mode &= ~current->fs->umask;
-       } else {
-               *acl = NULL;
+       ret = jffs2_init_acl_pre(dir_i, inode, &mode);
+       if (ret) {
+           make_bad_inode(inode);
+           iput(inode);
+           return ERR_PTR(ret);
        }
        ret = jffs2_do_new_inode (c, f, mode, ri);
        if (ret) {
index f6743a9..bf64686 100644 (file)
@@ -173,15 +173,13 @@ int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 extern const struct inode_operations jffs2_symlink_inode_operations;
 
 /* fs.c */
-struct posix_acl;
-
 int jffs2_setattr (struct dentry *, struct iattr *);
 int jffs2_do_setattr (struct inode *, struct iattr *);
 void jffs2_read_inode (struct inode *);
 void jffs2_clear_inode (struct inode *);
 void jffs2_dirty_inode(struct inode *inode);
 struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
-                              struct jffs2_raw_inode *ri, struct posix_acl **acl);
+                              struct jffs2_raw_inode *ri);
 int jffs2_statfs (struct dentry *, struct kstatfs *);
 void jffs2_write_super (struct super_block *);
 int jffs2_remount_fs (struct super_block *, int *, char *);
index 2f56954..147e2cb 100644 (file)
@@ -465,6 +465,14 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
 
        up(&f->sem);
        jffs2_complete_reservation(c);
+
+       ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode);
+       if (ret)
+               return ret;
+       ret = jffs2_init_acl_post(&f->vfs_inode);
+       if (ret)
+               return ret;
+
        ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
                                ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
 
index f0ec72b..8e2cf2c 100644 (file)
@@ -18,6 +18,8 @@
 #ifndef        _H_JFS_INODE
 #define _H_JFS_INODE
 
+struct fid;
+
 extern struct inode *ialloc(struct inode *, umode_t);
 extern int jfs_fsync(struct file *, struct dentry *, int);
 extern int jfs_ioctl(struct inode *, struct file *,
@@ -32,7 +34,10 @@ extern void jfs_truncate_nolock(struct inode *, loff_t);
 extern void jfs_free_zero_link(struct inode *);
 extern struct dentry *jfs_get_parent(struct dentry *dentry);
 extern void jfs_get_inode_flags(struct jfs_inode_info *);
-extern struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp);
+extern struct dentry *jfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+       int fh_len, int fh_type);
+extern struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
+       int fh_len, int fh_type);
 extern void jfs_set_inode_flags(struct inode *);
 extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
index 932797b..4e0a849 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include <linux/ctype.h>
 #include <linux/quotaops.h>
+#include <linux/exportfs.h>
 #include "jfs_incore.h"
 #include "jfs_superblock.h"
 #include "jfs_inode.h"
@@ -1477,13 +1478,10 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
        return dentry;
 }
 
-struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp)
+static struct inode *jfs_nfs_get_inode(struct super_block *sb,
+               u64 ino, u32 generation)
 {
-       __u32 *objp = vobjp;
-       unsigned long ino = objp[0];
-       __u32 generation = objp[1];
        struct inode *inode;
-       struct dentry *result;
 
        if (ino == 0)
                return ERR_PTR(-ESTALE);
@@ -1493,20 +1491,25 @@ struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp)
 
        if (is_bad_inode(inode) ||
            (generation && inode->i_generation != generation)) {
-               result = ERR_PTR(-ESTALE);
-               goto out_iput;
+               iput(inode);
+               return ERR_PTR(-ESTALE);
        }
 
-       result = d_alloc_anon(inode);
-       if (!result) {
-               result = ERR_PTR(-ENOMEM);
-               goto out_iput;
-       }
-       return result;
+       return inode;
+}
 
- out_iput:
-       iput(inode);
-       return result;
+struct dentry *jfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   jfs_nfs_get_inode);
+}
+
+struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   jfs_nfs_get_inode);
 }
 
 struct dentry *jfs_get_parent(struct dentry *dentry)
index cff60c1..314bb4f 100644 (file)
@@ -48,7 +48,7 @@ MODULE_LICENSE("GPL");
 static struct kmem_cache * jfs_inode_cachep;
 
 static const struct super_operations jfs_super_operations;
-static struct export_operations jfs_export_operations;
+static const struct export_operations jfs_export_operations;
 static struct file_system_type jfs_fs_type;
 
 #define MAX_COMMIT_THREADS 64
@@ -737,8 +737,9 @@ static const struct super_operations jfs_super_operations = {
 #endif
 };
 
-static struct export_operations jfs_export_operations = {
-       .get_dentry     = jfs_get_dentry,
+static const struct export_operations jfs_export_operations = {
+       .fh_to_dentry   = jfs_fh_to_dentry,
+       .fh_to_parent   = jfs_fh_to_parent,
        .get_parent     = jfs_get_parent,
 };
 
index ae51481..6e68b70 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/mount.h>
 #include <linux/vfs.h>
 #include <linux/mutex.h>
+#include <linux/exportfs.h>
 
 #include <asm/uaccess.h>
 
@@ -678,6 +679,93 @@ out:
        return ret;
 }
 
+/*
+ * This is what d_alloc_anon should have been.  Once the exportfs
+ * argument transition has been finished I will update d_alloc_anon
+ * to this prototype and this wrapper will go away.   --hch
+ */
+static struct dentry *exportfs_d_alloc(struct inode *inode)
+{
+       struct dentry *dentry;
+
+       if (!inode)
+               return NULL;
+       if (IS_ERR(inode))
+               return ERR_PTR(PTR_ERR(inode));
+
+       dentry = d_alloc_anon(inode);
+       if (!dentry) {
+               iput(inode);
+               dentry = ERR_PTR(-ENOMEM);
+       }
+       return dentry;
+}
+
+/**
+ * generic_fh_to_dentry - generic helper for the fh_to_dentry export operation
+ * @sb:                filesystem to do the file handle conversion on
+ * @fid:       file handle to convert
+ * @fh_len:    length of the file handle in bytes
+ * @fh_type:   type of file handle
+ * @get_inode: filesystem callback to retrieve inode
+ *
+ * This function decodes @fid as long as it has one of the well-known
+ * Linux filehandle types and calls @get_inode on it to retrieve the
+ * inode for the object specified in the file handle.
+ */
+struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type, struct inode *(*get_inode)
+                       (struct super_block *sb, u64 ino, u32 gen))
+{
+       struct inode *inode = NULL;
+
+       if (fh_len < 2)
+               return NULL;
+
+       switch (fh_type) {
+       case FILEID_INO32_GEN:
+       case FILEID_INO32_GEN_PARENT:
+               inode = get_inode(sb, fid->i32.ino, fid->i32.gen);
+               break;
+       }
+
+       return exportfs_d_alloc(inode);
+}
+EXPORT_SYMBOL_GPL(generic_fh_to_dentry);
+
+/**
+ * generic_fh_to_dentry - generic helper for the fh_to_parent export operation
+ * @sb:                filesystem to do the file handle conversion on
+ * @fid:       file handle to convert
+ * @fh_len:    length of the file handle in bytes
+ * @fh_type:   type of file handle
+ * @get_inode: filesystem callback to retrieve inode
+ *
+ * This function decodes @fid as long as it has one of the well-known
+ * Linux filehandle types and calls @get_inode on it to retrieve the
+ * inode for the _parent_ object specified in the file handle if it
+ * is specified in the file handle, or NULL otherwise.
+ */
+struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type, struct inode *(*get_inode)
+                       (struct super_block *sb, u64 ino, u32 gen))
+{
+       struct inode *inode = NULL;
+
+       if (fh_len <= 2)
+               return NULL;
+
+       switch (fh_type) {
+       case FILEID_INO32_GEN_PARENT:
+               inode = get_inode(sb, fid->i32.parent_ino,
+                                 (fh_len > 3 ? fid->i32.parent_gen : 0));
+               break;
+       }
+
+       return exportfs_d_alloc(inode);
+}
+EXPORT_SYMBOL_GPL(generic_fh_to_parent);
+
 EXPORT_SYMBOL(dcache_dir_close);
 EXPORT_SYMBOL(dcache_dir_lseek);
 EXPORT_SYMBOL(dcache_dir_open);
index 1e5c716..3b993db 100644 (file)
@@ -1174,7 +1174,7 @@ static int fastcall do_path_lookup(int dfd, const char *name,
 out:
        if (unlikely(!retval && !audit_dummy_context() && nd->dentry &&
                                nd->dentry->d_inode))
-               audit_inode(name, nd->dentry->d_inode);
+               audit_inode(name, nd->dentry);
 out_fail:
        return retval;
 
@@ -1214,7 +1214,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
        retval = path_walk(name, nd);
        if (unlikely(!retval && !audit_dummy_context() && nd->dentry &&
                                nd->dentry->d_inode))
-               audit_inode(name, nd->dentry->d_inode);
+               audit_inode(name, nd->dentry);
 
        return retval;
 
@@ -1469,7 +1469,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
                return -ENOENT;
 
        BUG_ON(victim->d_parent->d_inode != dir);
-       audit_inode_child(victim->d_name.name, victim->d_inode, dir);
+       audit_inode_child(victim->d_name.name, victim, dir);
 
        error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
        if (error)
@@ -1783,7 +1783,7 @@ do_last:
         * It already exists.
         */
        mutex_unlock(&dir->d_inode->i_mutex);
-       audit_inode(pathname, path.dentry->d_inode);
+       audit_inode(pathname, path.dentry);
 
        error = -EEXIST;
        if (flag & O_EXCL)
@@ -2562,7 +2562,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (!error) {
                const char *new_name = old_dentry->d_name.name;
                fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir,
-                             new_dentry->d_inode, old_dentry->d_inode);
+                             new_dentry->d_inode, old_dentry);
        }
        fsnotify_oldname_free(old_name);
 
index 8607529..0608388 100644 (file)
@@ -246,7 +246,7 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
                        list_add(&mnt->mnt_slave, &old->mnt_slave_list);
                        mnt->mnt_master = old;
                        CLEAR_MNT_SHARED(mnt);
-               } else {
+               } else if (!(flag & CL_PRIVATE)) {
                        if ((flag & CL_PROPAGATION) || IS_MNT_SHARED(old))
                                list_add(&mnt->mnt_share, &old->mnt_share);
                        if (IS_MNT_SLAVE(old))
@@ -746,6 +746,26 @@ Enomem:
        return NULL;
 }
 
+struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry)
+{
+       struct vfsmount *tree;
+       down_read(&namespace_sem);
+       tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE);
+       up_read(&namespace_sem);
+       return tree;
+}
+
+void drop_collected_mounts(struct vfsmount *mnt)
+{
+       LIST_HEAD(umount_list);
+       down_read(&namespace_sem);
+       spin_lock(&vfsmount_lock);
+       umount_tree(mnt, 0, &umount_list);
+       spin_unlock(&vfsmount_lock);
+       up_read(&namespace_sem);
+       release_mounts(&umount_list);
+}
+
 /*
  *  @source_mnt : mount tree to be attached
  *  @nd         : place the mount tree @source_mnt is attached
index 97669ed..4f80d88 100644 (file)
@@ -211,6 +211,7 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        nfs_fattr_init(&fattr);
        dprintk("NFS call  create %s\n", dentry->d_name.name);
        status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+       nfs_mark_for_revalidate(dir);
        if (status == 0)
                status = nfs_instantiate(dentry, &fhandle, &fattr);
        dprintk("NFS reply create: %d\n", status);
index ce558c2..233ad38 100644 (file)
@@ -171,7 +171,7 @@ static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
        if (parent == NULL)
                goto out_free;
        dir = parent->d_inode;
-       if (nfs_copy_dname(dentry, data) == 0)
+       if (nfs_copy_dname(dentry, data) != 0)
                goto out_dput;
        /* Non-exclusive lock protects against concurrent lookup() calls */
        spin_lock(&dir->i_lock);
index 04b2667..66d0aeb 100644 (file)
@@ -386,15 +386,13 @@ static int check_export(struct inode *inode, int flags, unsigned char *uuid)
                dprintk("exp_export: export of non-dev fs without fsid\n");
                return -EINVAL;
        }
-       if (!inode->i_sb->s_export_op) {
+
+       if (!inode->i_sb->s_export_op ||
+           !inode->i_sb->s_export_op->fh_to_dentry) {
                dprintk("exp_export: export of invalid fs type.\n");
                return -EINVAL;
        }
 
-       /* Ok, we can export it */;
-       if (!inode->i_sb->s_export_op->find_exported_dentry)
-               inode->i_sb->s_export_op->find_exported_dentry =
-                       find_exported_dentry;
        return 0;
 
 }
index ebd03cc..6f03918 100644 (file)
@@ -88,7 +88,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
 {
        struct xdr_netobj cksum;
        struct hash_desc desc;
-       struct scatterlist sg[1];
+       struct scatterlist sg;
        __be32 status = nfserr_resource;
 
        dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
@@ -102,11 +102,9 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
        if (cksum.data == NULL)
                goto out;
 
-       sg[0].page = virt_to_page(clname->data);
-       sg[0].offset = offset_in_page(clname->data);
-       sg[0].length = clname->len;
+       sg_init_one(&sg, clname->data, clname->len);
 
-       if (crypto_hash_digest(&desc, sg, sg->length, cksum.data))
+       if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data))
                goto out;
 
        md5_to_hex(dname, cksum.data);
index 7011d62..4f712e9 100644 (file)
@@ -115,8 +115,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
        dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
 
        if (!fhp->fh_dentry) {
-               __u32 *datap=NULL;
-               __u32 tfh[3];           /* filehandle fragment for oldstyle filehandles */
+               struct fid *fid = NULL, sfid;
                int fileid_type;
                int data_left = fh->fh_size/4;
 
@@ -128,7 +127,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
 
                if (fh->fh_version == 1) {
                        int len;
-                       datap = fh->fh_auth;
                        if (--data_left<0) goto out;
                        switch (fh->fh_auth_type) {
                        case 0: break;
@@ -144,9 +142,11 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                                fh->fh_fsid[1] = fh->fh_fsid[2];
                        }
                        if ((data_left -= len)<0) goto out;
-                       exp = rqst_exp_find(rqstp, fh->fh_fsid_type, datap);
-                       datap += len;
+                       exp = rqst_exp_find(rqstp, fh->fh_fsid_type,
+                                           fh->fh_auth);
+                       fid = (struct fid *)(fh->fh_auth + len);
                } else {
+                       __u32 tfh[2];
                        dev_t xdev;
                        ino_t xino;
                        if (fh->fh_size != NFS_FHSIZE)
@@ -190,22 +190,22 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                        error = nfserr_badhandle;
 
                if (fh->fh_version != 1) {
-                       tfh[0] = fh->ofh_ino;
-                       tfh[1] = fh->ofh_generation;
-                       tfh[2] = fh->ofh_dirino;
-                       datap = tfh;
+                       sfid.i32.ino = fh->ofh_ino;
+                       sfid.i32.gen = fh->ofh_generation;
+                       sfid.i32.parent_ino = fh->ofh_dirino;
+                       fid = &sfid;
                        data_left = 3;
                        if (fh->ofh_dirino == 0)
-                               fileid_type = 1;
+                               fileid_type = FILEID_INO32_GEN;
                        else
-                               fileid_type = 2;
+                               fileid_type = FILEID_INO32_GEN_PARENT;
                } else
                        fileid_type = fh->fh_fileid_type;
 
-               if (fileid_type == 0)
+               if (fileid_type == FILEID_ROOT)
                        dentry = dget(exp->ex_dentry);
                else {
-                       dentry = exportfs_decode_fh(exp->ex_mnt, datap,
+                       dentry = exportfs_decode_fh(exp->ex_mnt, fid,
                                        data_left, fileid_type,
                                        nfsd_acceptable, exp);
                }
@@ -286,16 +286,21 @@ out:
  * an inode.  In this case a call to fh_update should be made
  * before the fh goes out on the wire ...
  */
-static inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
-                            __u32 *datap, int *maxsize)
+static void _fh_update(struct svc_fh *fhp, struct svc_export *exp,
+               struct dentry *dentry)
 {
-       if (dentry == exp->ex_dentry) {
-               *maxsize = 0;
-               return 0;
-       }
+       if (dentry != exp->ex_dentry) {
+               struct fid *fid = (struct fid *)
+                       (fhp->fh_handle.fh_auth + fhp->fh_handle.fh_size/4 - 1);
+               int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
+               int subtreecheck = !(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
 
-       return exportfs_encode_fh(dentry, datap, maxsize,
-                         !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
+               fhp->fh_handle.fh_fileid_type =
+                       exportfs_encode_fh(dentry, fid, &maxsize, subtreecheck);
+               fhp->fh_handle.fh_size += maxsize * 4;
+       } else {
+               fhp->fh_handle.fh_fileid_type = FILEID_ROOT;
+       }
 }
 
 /*
@@ -457,12 +462,8 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
                datap += len/4;
                fhp->fh_handle.fh_size = 4 + len;
 
-               if (inode) {
-                       int size = (fhp->fh_maxsize-len-4)/4;
-                       fhp->fh_handle.fh_fileid_type =
-                               _fh_update(dentry, exp, datap, &size);
-                       fhp->fh_handle.fh_size += size*4;
-               }
+               if (inode)
+                       _fh_update(fhp, exp, dentry);
                if (fhp->fh_handle.fh_fileid_type == 255)
                        return nfserr_opnotsupp;
        }
@@ -479,7 +480,6 @@ __be32
 fh_update(struct svc_fh *fhp)
 {
        struct dentry *dentry;
-       __u32 *datap;
 
        if (!fhp->fh_dentry)
                goto out_bad;
@@ -490,15 +490,10 @@ fh_update(struct svc_fh *fhp)
        if (fhp->fh_handle.fh_version != 1) {
                _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle);
        } else {
-               int size;
-               if (fhp->fh_handle.fh_fileid_type != 0)
+               if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT)
                        goto out;
-               datap = fhp->fh_handle.fh_auth+
-                       fhp->fh_handle.fh_size/4 -1;
-               size = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
-               fhp->fh_handle.fh_fileid_type =
-                       _fh_update(dentry, fhp->fh_export, datap, &size);
-               fhp->fh_handle.fh_size += size*4;
+
+               _fh_update(fhp, fhp->fh_export, dentry);
                if (fhp->fh_handle.fh_fileid_type == 255)
                        return nfserr_opnotsupp;
        }
index e93c614..e1781c8 100644 (file)
@@ -450,58 +450,40 @@ try_next:
        return parent_dent;
 }
 
-/**
- * ntfs_get_dentry - find a dentry for the inode from a file handle sub-fragment
- * @sb:                super block identifying the mounted ntfs volume
- * @fh:                the file handle sub-fragment
- *
- * Find a dentry for the inode given a file handle sub-fragment.  This function
- * is called from fs/exportfs/expfs.c::find_exported_dentry() which in turn is
- * called from the default ->decode_fh() which is export_decode_fh() in the
- * same file.  The code is closely based on the default ->get_dentry() helper
- * fs/exportfs/expfs.c::get_object().
- *
- * The @fh contains two 32-bit unsigned values, the first one is the inode
- * number and the second one is the inode generation.
- *
- * Return the dentry on success or the error code on error (IS_ERR() is true).
- */
-static struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
+static struct inode *ntfs_nfs_get_inode(struct super_block *sb,
+               u64 ino, u32 generation)
 {
-       struct inode *vi;
-       struct dentry *dent;
-       unsigned long ino = ((u32 *)fh)[0];
-       u32 gen = ((u32 *)fh)[1];
+       struct inode *inode;
 
-       ntfs_debug("Entering for inode 0x%lx, generation 0x%x.", ino, gen);
-       vi = ntfs_iget(sb, ino);
-       if (IS_ERR(vi)) {
-               ntfs_error(sb, "Failed to get inode 0x%lx.", ino);
-               return (struct dentry *)vi;
-       }
-       if (unlikely(is_bad_inode(vi) || vi->i_generation != gen)) {
-               /* We didn't find the right inode. */
-               ntfs_error(sb, "Inode 0x%lx, bad count: %d %d or version 0x%x "
-                               "0x%x.", vi->i_ino, vi->i_nlink,
-                               atomic_read(&vi->i_count), vi->i_generation,
-                               gen);
-               iput(vi);
-               return ERR_PTR(-ESTALE);
-       }
-       /* Now find a dentry.  If possible, get a well-connected one. */
-       dent = d_alloc_anon(vi);
-       if (unlikely(!dent)) {
-               iput(vi);
-               return ERR_PTR(-ENOMEM);
+       inode = ntfs_iget(sb, ino);
+       if (!IS_ERR(inode)) {
+               if (is_bad_inode(inode) || inode->i_generation != generation) {
+                       iput(inode);
+                       inode = ERR_PTR(-ESTALE);
+               }
        }
-       ntfs_debug("Done for inode 0x%lx, generation 0x%x.", ino, gen);
-       return dent;
+
+       return inode;
+}
+
+static struct dentry *ntfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   ntfs_nfs_get_inode);
+}
+
+static struct dentry *ntfs_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   ntfs_nfs_get_inode);
 }
 
 /**
  * Export operations allowing NFS exporting of mounted NTFS partitions.
  *
- * We use the default ->decode_fh() and ->encode_fh() for now.  Note that they
+ * We use the default ->encode_fh() for now.  Note that they
  * use 32 bits to store the inode number which is an unsigned long so on 64-bit
  * architectures is usually 64 bits so it would all fail horribly on huge
  * volumes.  I guess we need to define our own encode and decode fh functions
@@ -517,10 +499,9 @@ static struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
  * allowing the inode number 0 which is used in NTFS for the system file $MFT
  * and due to using iget() whereas NTFS needs ntfs_iget().
  */
-struct export_operations ntfs_export_ops = {
+const struct export_operations ntfs_export_ops = {
        .get_parent     = ntfs_get_parent,      /* Find the parent of a given
                                                   directory. */
-       .get_dentry     = ntfs_get_dentry,      /* Find a dentry for the inode
-                                                  given a file handle
-                                                  sub-fragment. */
+       .fh_to_dentry   = ntfs_fh_to_dentry,
+       .fh_to_parent   = ntfs_fh_to_parent,
 };
index d73f5a9..d6a340b 100644 (file)
@@ -69,7 +69,7 @@ extern const struct inode_operations ntfs_dir_inode_ops;
 extern const struct  file_operations ntfs_empty_file_ops;
 extern const struct inode_operations ntfs_empty_inode_ops;
 
-extern struct export_operations ntfs_export_ops;
+extern const struct export_operations ntfs_export_ops;
 
 /**
  * NTFS_SB - return the ntfs volume given a vfs super block
index c3bbc19..535bfa9 100644 (file)
@@ -45,9 +45,9 @@ struct ocfs2_inode_handle
        u32 ih_generation;
 };
 
-static struct dentry *ocfs2_get_dentry(struct super_block *sb, void *vobjp)
+static struct dentry *ocfs2_get_dentry(struct super_block *sb,
+               struct ocfs2_inode_handle *handle)
 {
-       struct ocfs2_inode_handle *handle = vobjp;
        struct inode *inode;
        struct dentry *result;
 
@@ -194,54 +194,37 @@ bail:
        return type;
 }
 
-static struct dentry *ocfs2_decode_fh(struct super_block *sb, u32 *fh_in,
-                                     int fh_len, int fileid_type,
-                                     int (*acceptable)(void *context,
-                                                       struct dentry *de),
-                                     void *context)
+static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
+               struct fid *fid, int fh_len, int fh_type)
 {
-       struct ocfs2_inode_handle handle, parent;
-       struct dentry *ret = NULL;
-       __le32 *fh = (__force __le32 *) fh_in;
-
-       mlog_entry("(0x%p, 0x%p, %d, %d, 0x%p, 0x%p)\n",
-                  sb, fh, fh_len, fileid_type, acceptable, context);
-
-       if (fh_len < 3 || fileid_type > 2)
-               goto bail;
-
-       if (fileid_type == 2) {
-               if (fh_len < 6)
-                       goto bail;
-
-               parent.ih_blkno = (u64)le32_to_cpu(fh[3]) << 32;
-               parent.ih_blkno |= (u64)le32_to_cpu(fh[4]);
-               parent.ih_generation = le32_to_cpu(fh[5]);
+       struct ocfs2_inode_handle handle;
 
-               mlog(0, "Decoding parent: blkno: %llu, generation: %u\n",
-                    (unsigned long long)parent.ih_blkno,
-                    parent.ih_generation);
-       }
+       if (fh_len < 3 || fh_type > 2)
+               return NULL;
 
-       handle.ih_blkno = (u64)le32_to_cpu(fh[0]) << 32;
-       handle.ih_blkno |= (u64)le32_to_cpu(fh[1]);
-       handle.ih_generation = le32_to_cpu(fh[2]);
+       handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32;
+       handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]);
+       handle.ih_generation = le32_to_cpu(fid->raw[2]);
+       return ocfs2_get_dentry(sb, &handle);
+}
 
-       mlog(0, "Encoding fh: blkno: %llu, generation: %u\n",
-            (unsigned long long)handle.ih_blkno, handle.ih_generation);
+static struct dentry *ocfs2_fh_to_parent(struct super_block *sb,
+               struct fid *fid, int fh_len, int fh_type)
+{
+       struct ocfs2_inode_handle parent;
 
-       ret = ocfs2_export_ops.find_exported_dentry(sb, &handle, &parent,
-                                                   acceptable, context);
+       if (fh_type != 2 || fh_len < 6)
+               return NULL;
 
-bail:
-       mlog_exit_ptr(ret);
-       return ret;
+       parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32;
+       parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]);
+       parent.ih_generation = le32_to_cpu(fid->raw[5]);
+       return ocfs2_get_dentry(sb, &parent);
 }
 
-struct export_operations ocfs2_export_ops = {
-       .decode_fh      = ocfs2_decode_fh,
+const struct export_operations ocfs2_export_ops = {
        .encode_fh      = ocfs2_encode_fh,
-
+       .fh_to_dentry   = ocfs2_fh_to_dentry,
+       .fh_to_parent   = ocfs2_fh_to_parent,
        .get_parent     = ocfs2_get_parent,
-       .get_dentry     = ocfs2_get_dentry,
 };
index e08bed9..41a7386 100644 (file)
@@ -28,6 +28,6 @@
 
 #include <linux/exportfs.h>
 
-extern struct export_operations ocfs2_export_ops;
+extern const struct export_operations ocfs2_export_ops;
 
 #endif /* OCFS2_EXPORT_H */
index 7538514..3b69c53 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -569,7 +569,7 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
        dentry = file->f_path.dentry;
        inode = dentry->d_inode;
 
-       audit_inode(NULL, inode);
+       audit_inode(NULL, dentry);
 
        err = -EROFS;
        if (IS_RDONLY(inode))
@@ -727,7 +727,7 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
                goto out;
 
        dentry = file->f_path.dentry;
-       audit_inode(NULL, dentry->d_inode);
+       audit_inode(NULL, dentry);
        error = chown_common(dentry, user, group);
        fput(file);
 out:
index d45bd8e..f249be2 100644 (file)
@@ -22,6 +22,7 @@
 #define CL_COPY_ALL            0x04
 #define CL_MAKE_SHARED                 0x08
 #define CL_PROPAGATION                 0x10
+#define CL_PRIVATE             0x20
 
 static inline void set_mnt_shared(struct vfsmount *mnt)
 {
index 39a3d7c..aeaf0d0 100644 (file)
@@ -2255,27 +2255,6 @@ static const struct inode_operations proc_tgid_base_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-/**
- * proc_flush_task -  Remove dcache entries for @task from the /proc dcache.
- *
- * @task: task that should be flushed.
- *
- * Looks in the dcache for
- * /proc/@pid
- * /proc/@tgid/task/@pid
- * if either directory is present flushes it and all of it'ts children
- * from the dcache.
- *
- * It is safe and reasonable to cache /proc entries for a task until
- * that task exits.  After that they just clog up the dcache with
- * useless entries, possibly causing useful dcache entries to be
- * flushed instead.  This routine is proved to flush those useless
- * dcache entries at process exit time.
- *
- * NOTE: This routine is just an optimization so it does not guarantee
- *       that no dcache entries will exist at process exit time it
- *       just makes it very unlikely that any will persist.
- */
 static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
 {
        struct dentry *dentry, *leader, *dir;
@@ -2322,10 +2301,29 @@ out:
        return;
 }
 
-/*
- * when flushing dentries from proc one need to flush them from global
+/**
+ * proc_flush_task -  Remove dcache entries for @task from the /proc dcache.
+ * @task: task that should be flushed.
+ *
+ * When flushing dentries from proc, one needs to flush them from global
  * proc (proc_mnt) and from all the namespaces' procs this task was seen
- * in. this call is supposed to make all this job.
+ * in. This call is supposed to do all of this job.
+ *
+ * Looks in the dcache for
+ * /proc/@pid
+ * /proc/@tgid/task/@pid
+ * if either directory is present flushes it and all of it'ts children
+ * from the dcache.
+ *
+ * It is safe and reasonable to cache /proc entries for a task until
+ * that task exits.  After that they just clog up the dcache with
+ * useless entries, possibly causing useful dcache entries to be
+ * flushed instead.  This routine is proved to flush those useless
+ * dcache entries at process exit time.
+ *
+ * NOTE: This routine is just an optimization so it does not guarantee
+ *       that no dcache entries will exist at process exit time it
+ *       just makes it very unlikely that any will persist.
  */
 
 void proc_flush_task(struct task_struct *task)
index a991af9..231fd5c 100644 (file)
@@ -1515,19 +1515,20 @@ struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key)
        return inode;
 }
 
-struct dentry *reiserfs_get_dentry(struct super_block *sb, void *vobjp)
+static struct dentry *reiserfs_get_dentry(struct super_block *sb,
+       u32 objectid, u32 dir_id, u32 generation)
+
 {
-       __u32 *data = vobjp;
        struct cpu_key key;
        struct dentry *result;
        struct inode *inode;
 
-       key.on_disk_key.k_objectid = data[0];
-       key.on_disk_key.k_dir_id = data[1];
+       key.on_disk_key.k_objectid = objectid;
+       key.on_disk_key.k_dir_id = dir_id;
        reiserfs_write_lock(sb);
        inode = reiserfs_iget(sb, &key);
-       if (inode && !IS_ERR(inode) && data[2] != 0 &&
-           data[2] != inode->i_generation) {
+       if (inode && !IS_ERR(inode) && generation != 0 &&
+           generation != inode->i_generation) {
                iput(inode);
                inode = NULL;
        }
@@ -1544,14 +1545,9 @@ struct dentry *reiserfs_get_dentry(struct super_block *sb, void *vobjp)
        return result;
 }
 
-struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 * data,
-                                 int len, int fhtype,
-                                 int (*acceptable) (void *contect,
-                                                    struct dentry * de),
-                                 void *context)
+struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
 {
-       __u32 obj[3], parent[3];
-
        /* fhtype happens to reflect the number of u32s encoded.
         * due to a bug in earlier code, fhtype might indicate there
         * are more u32s then actually fitted.
@@ -1564,32 +1560,28 @@ struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 * data,
         *   6 - as above plus generation of directory
         * 6 does not fit in NFSv2 handles
         */
-       if (fhtype > len) {
-               if (fhtype != 6 || len != 5)
+       if (fh_type > fh_len) {
+               if (fh_type != 6 || fh_len != 5)
                        reiserfs_warning(sb,
-                                        "nfsd/reiserfs, fhtype=%d, len=%d - odd",
-                                        fhtype, len);
-               fhtype = 5;
+                               "nfsd/reiserfs, fhtype=%d, len=%d - odd",
+                               fh_type, fh_len);
+               fh_type = 5;
        }
 
-       obj[0] = data[0];
-       obj[1] = data[1];
-       if (fhtype == 3 || fhtype >= 5)
-               obj[2] = data[2];
-       else
-               obj[2] = 0;     /* generation number */
+       return reiserfs_get_dentry(sb, fid->raw[0], fid->raw[1],
+               (fh_type == 3 || fh_type >= 5) ? fid->raw[2] : 0);
+}
 
-       if (fhtype >= 4) {
-               parent[0] = data[fhtype >= 5 ? 3 : 2];
-               parent[1] = data[fhtype >= 5 ? 4 : 3];
-               if (fhtype == 6)
-                       parent[2] = data[5];
-               else
-                       parent[2] = 0;
-       }
-       return sb->s_export_op->find_exported_dentry(sb, obj,
-                                                    fhtype < 4 ? NULL : parent,
-                                                    acceptable, context);
+struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       if (fh_type < 4)
+               return NULL;
+
+       return reiserfs_get_dentry(sb,
+               (fh_type >= 5) ? fid->raw[3] : fid->raw[2],
+               (fh_type >= 5) ? fid->raw[4] : fid->raw[3],
+               (fh_type == 6) ? fid->raw[5] : 0);
 }
 
 int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
index 98c3781..5cd85fe 100644 (file)
@@ -661,11 +661,11 @@ static struct quotactl_ops reiserfs_qctl_operations = {
 };
 #endif
 
-static struct export_operations reiserfs_export_ops = {
+static const struct export_operations reiserfs_export_ops = {
        .encode_fh = reiserfs_encode_fh,
-       .decode_fh = reiserfs_decode_fh,
+       .fh_to_dentry = reiserfs_fh_to_dentry,
+       .fh_to_parent = reiserfs_fh_to_parent,
        .get_parent = reiserfs_get_parent,
-       .get_dentry = reiserfs_get_dentry,
 };
 
 /* this struct is used in reiserfs_getopt () for containing the value for those
index a44fd92..6645b73 100644 (file)
@@ -267,7 +267,7 @@ sys_fsetxattr(int fd, char __user *name, void __user *value,
        if (!f)
                return error;
        dentry = f->f_path.dentry;
-       audit_inode(NULL, dentry->d_inode);
+       audit_inode(NULL, dentry);
        error = setxattr(dentry, name, value, size, flags);
        fput(f);
        return error;
@@ -349,7 +349,7 @@ sys_fgetxattr(int fd, char __user *name, void __user *value, size_t size)
        f = fget(fd);
        if (!f)
                return error;
-       audit_inode(NULL, f->f_path.dentry->d_inode);
+       audit_inode(NULL, f->f_path.dentry);
        error = getxattr(f->f_path.dentry, name, value, size);
        fput(f);
        return error;
@@ -422,7 +422,7 @@ sys_flistxattr(int fd, char __user *list, size_t size)
        f = fget(fd);
        if (!f)
                return error;
-       audit_inode(NULL, f->f_path.dentry->d_inode);
+       audit_inode(NULL, f->f_path.dentry);
        error = listxattr(f->f_path.dentry, list, size);
        fput(f);
        return error;
@@ -485,7 +485,7 @@ sys_fremovexattr(int fd, char __user *name)
        if (!f)
                return error;
        dentry = f->f_path.dentry;
-       audit_inode(NULL, dentry->d_inode);
+       audit_inode(NULL, dentry);
        error = removexattr(dentry, name);
        fput(f);
        return error;
index 3586c7a..15bd494 100644 (file)
 static struct dentry dotdot = { .d_name.name = "..", .d_name.len = 2, };
 
 /*
- * XFS encodes and decodes the fileid portion of NFS filehandles
- * itself instead of letting the generic NFS code do it.  This
- * allows filesystems with 64 bit inode numbers to be exported.
- *
- * Note that a side effect is that xfs_vget() won't be passed a
- * zero inode/generation pair under normal circumstances.  As
- * however a malicious client could send us such data, the check
- * remains in that code.
+ * Note that we only accept fileids which are long enough rather than allow
+ * the parent generation number to default to zero.  XFS considers zero a
+ * valid generation number not an invalid/wildcard value.
  */
-
-STATIC struct dentry *
-xfs_fs_decode_fh(
-       struct super_block      *sb,
-       __u32                   *fh,
-       int                     fh_len,
-       int                     fileid_type,
-       int (*acceptable)(
-               void            *context,
-               struct dentry   *de),
-       void                    *context)
+static int xfs_fileid_length(int fileid_type)
 {
-       xfs_fid_t               ifid;
-       xfs_fid_t               pfid;
-       void                    *parent = NULL;
-       int                     is64 = 0;
-       __u32                   *p = fh;
-
-#if XFS_BIG_INUMS
-       is64 = (fileid_type & XFS_FILEID_TYPE_64FLAG);
-       fileid_type &= ~XFS_FILEID_TYPE_64FLAG;
-#endif
-
-       /*
-        * Note that we only accept fileids which are long enough
-        * rather than allow the parent generation number to default
-        * to zero.  XFS considers zero a valid generation number not
-        * an invalid/wildcard value.  There's little point printk'ing
-        * a warning here as we don't have the client information
-        * which would make such a warning useful.
-        */
-       if (fileid_type > 2 ||
-           fh_len < xfs_fileid_length((fileid_type == 2), is64))
-               return NULL;
-
-       p = xfs_fileid_decode_fid2(p, &ifid, is64);
-
-       if (fileid_type == 2) {
-               p = xfs_fileid_decode_fid2(p, &pfid, is64);
-               parent = &pfid;
+       switch (fileid_type) {
+       case FILEID_INO32_GEN:
+               return 2;
+       case FILEID_INO32_GEN_PARENT:
+               return 4;
+       case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
+               return 3;
+       case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
+               return 6;
        }
-
-       fh = (__u32 *)&ifid;
-       return sb->s_export_op->find_exported_dentry(sb, fh, parent, acceptable, context);
+       return 255; /* invalid */
 }
 
-
 STATIC int
 xfs_fs_encode_fh(
        struct dentry           *dentry,
@@ -96,21 +59,21 @@ xfs_fs_encode_fh(
        int                     *max_len,
        int                     connectable)
 {
+       struct fid              *fid = (struct fid *)fh;
+       struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fh;
        struct inode            *inode = dentry->d_inode;
-       int                     type = 1;
-       __u32                   *p = fh;
+       int                     fileid_type;
        int                     len;
-       int                     is64 = 0;
-#if XFS_BIG_INUMS
-       if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS)) {
-               /* filesystem may contain 64bit inode numbers */
-               is64 = XFS_FILEID_TYPE_64FLAG;
-       }
-#endif
 
        /* Directories don't need their parent encoded, they have ".." */
        if (S_ISDIR(inode->i_mode))
-           connectable = 0;
+               fileid_type = FILEID_INO32_GEN;
+       else
+               fileid_type = FILEID_INO32_GEN_PARENT;
+
+       /* filesystem may contain 64bit inode numbers */
+       if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS))
+               fileid_type |= XFS_FILEID_TYPE_64FLAG;
 
        /*
         * Only encode if there is enough space given.  In practice
@@ -118,39 +81,118 @@ xfs_fs_encode_fh(
         * over NFSv2 with the subtree_check export option; the other
         * seven combinations work.  The real answer is "don't use v2".
         */
-       len = xfs_fileid_length(connectable, is64);
+       len = xfs_fileid_length(fileid_type);
        if (*max_len < len)
                return 255;
        *max_len = len;
 
-       p = xfs_fileid_encode_inode(p, inode, is64);
-       if (connectable) {
+       switch (fileid_type) {
+       case FILEID_INO32_GEN_PARENT:
                spin_lock(&dentry->d_lock);
-               p = xfs_fileid_encode_inode(p, dentry->d_parent->d_inode, is64);
+               fid->i32.parent_ino = dentry->d_parent->d_inode->i_ino;
+               fid->i32.parent_gen = dentry->d_parent->d_inode->i_generation;
                spin_unlock(&dentry->d_lock);
-               type = 2;
+               /*FALLTHRU*/
+       case FILEID_INO32_GEN:
+               fid->i32.ino = inode->i_ino;
+               fid->i32.gen = inode->i_generation;
+               break;
+       case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
+               spin_lock(&dentry->d_lock);
+               fid64->parent_ino = dentry->d_parent->d_inode->i_ino;
+               fid64->parent_gen = dentry->d_parent->d_inode->i_generation;
+               spin_unlock(&dentry->d_lock);
+               /*FALLTHRU*/
+       case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
+               fid64->ino = inode->i_ino;
+               fid64->gen = inode->i_generation;
+               break;
        }
-       BUG_ON((p - fh) != len);
-       return type | is64;
+
+       return fileid_type;
 }
 
-STATIC struct dentry *
-xfs_fs_get_dentry(
+STATIC struct inode *
+xfs_nfs_get_inode(
        struct super_block      *sb,
-       void                    *data)
-{
+       u64                     ino,
+       u32                     generation)
+ {
+       xfs_fid_t               xfid;
        bhv_vnode_t             *vp;
-       struct inode            *inode;
-       struct dentry           *result;
        int                     error;
 
-       error = xfs_vget(XFS_M(sb), &vp, data);
-       if (error || vp == NULL)
-               return ERR_PTR(-ESTALE) ;
+       xfid.fid_len = sizeof(xfs_fid_t) - sizeof(xfid.fid_len);
+       xfid.fid_pad = 0;
+       xfid.fid_ino = ino;
+       xfid.fid_gen = generation;
 
-       inode = vn_to_inode(vp);
+       error = xfs_vget(XFS_M(sb), &vp, &xfid);
+       if (error)
+               return ERR_PTR(-error);
+
+       return vp ? vn_to_inode(vp) : NULL;
+}
+
+STATIC struct dentry *
+xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+                int fh_len, int fileid_type)
+{
+       struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fid;
+       struct inode            *inode = NULL;
+       struct dentry           *result;
+
+       if (fh_len < xfs_fileid_length(fileid_type))
+               return NULL;
+
+       switch (fileid_type) {
+       case FILEID_INO32_GEN_PARENT:
+       case FILEID_INO32_GEN:
+               inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
+               break;
+       case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
+       case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
+               inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
+               break;
+       }
+
+       if (!inode)
+               return NULL;
+       if (IS_ERR(inode))
+               return ERR_PTR(PTR_ERR(inode));
+       result = d_alloc_anon(inode);
+       if (!result) {
+               iput(inode);
+               return ERR_PTR(-ENOMEM);
+       }
+       return result;
+}
+
+STATIC struct dentry *
+xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
+                int fh_len, int fileid_type)
+{
+       struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fid;
+       struct inode            *inode = NULL;
+       struct dentry           *result;
+
+       switch (fileid_type) {
+       case FILEID_INO32_GEN_PARENT:
+               inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
+                                             fid->i32.parent_gen);
+               break;
+       case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
+               inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
+                                             fid64->parent_gen);
+               break;
+       }
+
+       if (!inode)
+               return NULL;
+       if (IS_ERR(inode))
+               return ERR_PTR(PTR_ERR(inode));
        result = d_alloc_anon(inode);
-        if (!result) {
+       if (!result) {
                iput(inode);
                return ERR_PTR(-ENOMEM);
        }
@@ -178,9 +220,9 @@ xfs_fs_get_parent(
        return parent;
 }
 
-struct export_operations xfs_export_operations = {
-       .decode_fh              = xfs_fs_decode_fh,
+const struct export_operations xfs_export_operations = {
        .encode_fh              = xfs_fs_encode_fh,
+       .fh_to_dentry           = xfs_fs_fh_to_dentry,
+       .fh_to_parent           = xfs_fs_fh_to_parent,
        .get_parent             = xfs_fs_get_parent,
-       .get_dentry             = xfs_fs_get_dentry,
 };
index 2f36071..3272b6a 100644 (file)
  * a subdirectory) or use the "fsid" export option.
  */
 
+struct xfs_fid64 {
+       u64 ino;
+       u32 gen;
+       u64 parent_ino;
+       u32 parent_gen;
+} __attribute__((packed));
+
 /* This flag goes on the wire.  Don't play with it. */
 #define XFS_FILEID_TYPE_64FLAG 0x80    /* NFS fileid has 64bit inodes */
 
-/* Calculate the length in u32 units of the fileid data */
-static inline int
-xfs_fileid_length(int hasparent, int is64)
-{
-       return hasparent ? (is64 ? 6 : 4) : (is64 ? 3 : 2);
-}
-
-/*
- * Decode encoded inode information (either for the inode itself
- * or the parent) into an xfs_fid_t structure.  Advances and
- * returns the new data pointer
- */
-static inline __u32 *
-xfs_fileid_decode_fid2(__u32 *p, xfs_fid_t *fid, int is64)
-{
-       fid->fid_len = sizeof(xfs_fid_t) - sizeof(fid->fid_len);
-       fid->fid_pad = 0;
-       fid->fid_ino = *p++;
-#if XFS_BIG_INUMS
-       if (is64)
-               fid->fid_ino |= (((__u64)(*p++)) << 32);
-#endif
-       fid->fid_gen = *p++;
-       return p;
-}
-
-/*
- * Encode inode information (either for the inode itself or the
- * parent) into a fileid buffer.  Advances and returns the new
- * data pointer.
- */
-static inline __u32 *
-xfs_fileid_encode_inode(__u32 *p, struct inode *inode, int is64)
-{
-       *p++ = (__u32)inode->i_ino;
-#if XFS_BIG_INUMS
-       if (is64)
-               *p++ = (__u32)(inode->i_ino >> 32);
-#endif
-       *p++ = inode->i_generation;
-       return p;
-}
-
 #endif /* __XFS_EXPORT_H__ */
index c78c233..3efcf45 100644 (file)
@@ -118,7 +118,7 @@ extern int  xfs_blkdev_get(struct xfs_mount *, const char *,
 extern void xfs_blkdev_put(struct block_device *);
 extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
 
-extern struct export_operations xfs_export_operations;
+extern const struct export_operations xfs_export_operations;
 
 #define XFS_M(sb)              ((struct xfs_mount *)((sb)->s_fs_info))
 
index 4e5d3ca..a1b1b2e 100644 (file)
@@ -257,7 +257,8 @@ struct acpi_table_dbgp {
 struct acpi_table_dmar {
        struct acpi_table_header header;        /* Common ACPI table header */
        u8 width;               /* Host Address Width */
-       u8 reserved[11];
+       u8 flags;
+       u8 reserved[10];
 };
 
 /* DMAR subtable header */
@@ -265,8 +266,6 @@ struct acpi_table_dmar {
 struct acpi_dmar_header {
        u16 type;
        u16 length;
-       u8 flags;
-       u8 reserved[3];
 };
 
 /* Values for subtable type in struct acpi_dmar_header */
@@ -274,13 +273,15 @@ struct acpi_dmar_header {
 enum acpi_dmar_type {
        ACPI_DMAR_TYPE_HARDWARE_UNIT = 0,
        ACPI_DMAR_TYPE_RESERVED_MEMORY = 1,
-       ACPI_DMAR_TYPE_RESERVED = 2     /* 2 and greater are reserved */
+       ACPI_DMAR_TYPE_ATSR = 2,
+       ACPI_DMAR_TYPE_RESERVED = 3     /* 3 and greater are reserved */
 };
 
 struct acpi_dmar_device_scope {
        u8 entry_type;
        u8 length;
-       u8 segment;
+       u16 reserved;
+       u8 enumeration_id;
        u8 bus;
 };
 
@@ -290,7 +291,14 @@ enum acpi_dmar_scope_type {
        ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0,
        ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1,
        ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2,
-       ACPI_DMAR_SCOPE_TYPE_RESERVED = 3       /* 3 and greater are reserved */
+       ACPI_DMAR_SCOPE_TYPE_IOAPIC = 3,
+       ACPI_DMAR_SCOPE_TYPE_HPET = 4,
+       ACPI_DMAR_SCOPE_TYPE_RESERVED = 5       /* 5 and greater are reserved */
+};
+
+struct acpi_dmar_pci_path {
+       u8 dev;
+       u8 fn;
 };
 
 /*
@@ -301,6 +309,9 @@ enum acpi_dmar_scope_type {
 
 struct acpi_dmar_hardware_unit {
        struct acpi_dmar_header header;
+       u8 flags;
+       u8 reserved;
+       u16 segment;
        u64 address;            /* Register Base Address */
 };
 
@@ -312,7 +323,9 @@ struct acpi_dmar_hardware_unit {
 
 struct acpi_dmar_reserved_memory {
        struct acpi_dmar_header header;
-       u64 address;            /* 4_k aligned base address */
+       u16 reserved;
+       u16 segment;
+       u64 base_address;               /* 4_k aligned base address */
        u64 end_address;        /* 4_k aligned limit address */
 };
 
index 9173654..440747c 100644 (file)
@@ -5,7 +5,10 @@
 #include <asm/types.h>
   
 struct scatterlist {
-       struct page *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long sg_magic;
+#endif
+       unsigned long page_link;
        unsigned int offset;
 
        unsigned int length;
index 1eb8aac..e99406a 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/mm.h> /* need struct page */
 
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 /*
  * DMA-consistent mapping functions.  These allocate/free a region of
@@ -274,8 +274,8 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        for (i = 0; i < nents; i++, sg++) {
                char *virt;
 
-               sg->dma_address = page_to_dma(dev, sg->page) + sg->offset;
-               virt = page_address(sg->page) + sg->offset;
+               sg->dma_address = page_to_dma(dev, sg_page(sg)) + sg->offset;
+               virt = sg_virt(sg);
 
                if (!arch_is_coherent())
                        dma_cache_maint(virt, sg->length, dir);
@@ -371,7 +371,7 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
        int i;
 
        for (i = 0; i < nents; i++, sg++) {
-               char *virt = page_address(sg->page) + sg->offset;
+               char *virt = sg_virt(sg);
                if (!arch_is_coherent())
                        dma_cache_maint(virt, sg->length, dir);
        }
@@ -384,7 +384,7 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
        int i;
 
        for (i = 0; i < nents; i++, sg++) {
-               char *virt = page_address(sg->page) + sg->offset;
+               char *virt = sg_virt(sg);
                if (!arch_is_coherent())
                        dma_cache_maint(virt, sg->length, dir);
        }
index de2f65e..ca0a37d 100644 (file)
@@ -5,7 +5,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-       struct page     *page;          /* buffer page                   */
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
        unsigned int    offset;         /* buffer offset                 */
        dma_addr_t      dma_address;    /* dma address                   */
        unsigned int    length;         /* length                        */
index 7dbd603..d6993a6 100644 (file)
@@ -44,6 +44,13 @@ struct usba_platform_data {
 struct platform_device *
 at32_add_device_usba(unsigned int id, struct usba_platform_data *data);
 
+struct ide_platform_data {
+       u8      cs;
+};
+struct platform_device *
+at32_add_device_ide(unsigned int id, unsigned int extint,
+                   struct ide_platform_data *data);
+
 /* depending on what's hooked up, not all SSC pins will be used */
 #define        ATMEL_SSC_TK            0x01
 #define        ATMEL_SSC_TF            0x02
@@ -58,4 +65,20 @@ at32_add_device_usba(unsigned int id, struct usba_platform_data *data);
 struct platform_device *
 at32_add_device_ssc(unsigned int id, unsigned int flags);
 
+struct platform_device *at32_add_device_twi(unsigned int id);
+struct platform_device *at32_add_device_mci(unsigned int id);
+struct platform_device *at32_add_device_ac97c(unsigned int id);
+struct platform_device *at32_add_device_abdac(unsigned int id);
+
+struct cf_platform_data {
+       int     detect_pin;
+       int     reset_pin;
+       int     vcc_pin;
+       int     ready_pin;
+       u8      cs;
+};
+struct platform_device *
+at32_add_device_cf(unsigned int id, unsigned int extint,
+               struct cf_platform_data *data);
+
 #endif /* __ASM_ARCH_BOARD_H */
index 81e3426..a713163 100644 (file)
@@ -217,8 +217,8 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        for (i = 0; i < nents; i++) {
                char *virt;
 
-               sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset;
-               virt = page_address(sg[i].page) + sg[i].offset;
+               sg[i].dma_address = page_to_bus(sg_page(&sg[i])) + sg[i].offset;
+               virt = sg_virt(&sg[i]);
                dma_cache_sync(dev, virt, sg[i].length, direction);
        }
 
@@ -327,8 +327,7 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
        int i;
 
        for (i = 0; i < nents; i++) {
-               dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
-                              sg[i].length, direction);
+               dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, direction);
        }
 }
 
index c6d5ce3..377320e 100644 (file)
@@ -4,7 +4,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-    struct page                *page;
+#ifdef CONFIG_DEBUG_SG
+   unsigned long       sg_magic;
+#endif
+    unsigned long      page_link;
     unsigned int       offset;
     dma_addr_t         dma_address;
     unsigned int       length;
diff --git a/include/asm-blackfin/bf5xx_timers.h b/include/asm-blackfin/bf5xx_timers.h
deleted file mode 100644 (file)
index 86c7703..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * include/asm/bf5xx_timers.h
- *
- * This file contains the major Data structures and constants
- * used for General Purpose Timer Implementation in BF5xx
- *
- * Copyright (C) 2005 John DeHority
- * Copyright (C) 2006 Hella Aglaia GmbH (awe@aglaia-gmbh.de)
- *
- */
-
-#ifndef _BLACKFIN_TIMERS_H_
-#define _BLACKFIN_TIMERS_H_
-
-#undef MAX_BLACKFIN_GPTIMERS
-/*
- * BF537: 8 timers:
- */
-#if defined(CONFIG_BF537)
-#  define MAX_BLACKFIN_GPTIMERS 8
-#  define TIMER0_GROUP_REG     TIMER_ENABLE
-#endif
-/*
- * BF561: 12 timers:
- */
-#if defined(CONFIG_BF561)
-#  define MAX_BLACKFIN_GPTIMERS 12
-#  define TIMER0_GROUP_REG     TMRS8_ENABLE
-#  define TIMER8_GROUP_REG     TMRS4_ENABLE
-#endif
-/*
- * All others: 3 timers:
- */
-#if !defined(MAX_BLACKFIN_GPTIMERS)
-#  define MAX_BLACKFIN_GPTIMERS 3
-#  define TIMER0_GROUP_REG     TIMER_ENABLE
-#endif
-
-#define BLACKFIN_GPTIMER_IDMASK ((1UL << MAX_BLACKFIN_GPTIMERS) - 1)
-#define BFIN_TIMER_OCTET(x) ((x) >> 3)
-
-/* used in masks for timer_enable() and timer_disable() */
-#define TIMER0bit  0x0001  /*  0001b */
-#define TIMER1bit  0x0002  /*  0010b */
-#define TIMER2bit  0x0004  /*  0100b */
-
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-#  define TIMER3bit  0x0008
-#  define TIMER4bit  0x0010
-#  define TIMER5bit  0x0020
-#  define TIMER6bit  0x0040
-#  define TIMER7bit  0x0080
-#endif
-
-#if (MAX_BLACKFIN_GPTIMERS > 8)
-#  define TIMER8bit  0x0100
-#  define TIMER9bit  0x0200
-#  define TIMER10bit 0x0400
-#  define TIMER11bit 0x0800
-#endif
-
-#define TIMER0_id   0
-#define TIMER1_id   1
-#define TIMER2_id   2
-
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-#  define TIMER3_id   3
-#  define TIMER4_id   4
-#  define TIMER5_id   5
-#  define TIMER6_id   6
-#  define TIMER7_id   7
-#endif
-
-#if (MAX_BLACKFIN_GPTIMERS > 8)
-#  define TIMER8_id   8
-#  define TIMER9_id   9
-#  define TIMER10_id 10
-#  define TIMER11_id 11
-#endif
-
-/* associated timers for ppi framesync: */
-
-#if defined(CONFIG_BF561)
-#  define FS0_1_TIMER_ID   TIMER8_id
-#  define FS0_2_TIMER_ID   TIMER9_id
-#  define FS1_1_TIMER_ID   TIMER10_id
-#  define FS1_2_TIMER_ID   TIMER11_id
-#  define FS0_1_TIMER_BIT  TIMER8bit
-#  define FS0_2_TIMER_BIT  TIMER9bit
-#  define FS1_1_TIMER_BIT  TIMER10bit
-#  define FS1_2_TIMER_BIT  TIMER11bit
-#  undef FS1_TIMER_ID
-#  undef FS2_TIMER_ID
-#  undef FS1_TIMER_BIT
-#  undef FS2_TIMER_BIT
-#else
-#  define FS1_TIMER_ID  TIMER0_id
-#  define FS2_TIMER_ID  TIMER1_id
-#  define FS1_TIMER_BIT TIMER0bit
-#  define FS2_TIMER_BIT TIMER1bit
-#endif
-
-/*
-** Timer Configuration Register Bits
-*/
-#define TIMER_ERR           0xC000
-#define TIMER_ERR_OVFL      0x4000
-#define TIMER_ERR_PROG_PER  0x8000
-#define TIMER_ERR_PROG_PW   0xC000
-#define TIMER_EMU_RUN       0x0200
-#define        TIMER_TOGGLE_HI     0x0100
-#define        TIMER_CLK_SEL       0x0080
-#define TIMER_OUT_DIS       0x0040
-#define TIMER_TIN_SEL       0x0020
-#define TIMER_IRQ_ENA       0x0010
-#define TIMER_PERIOD_CNT    0x0008
-#define TIMER_PULSE_HI      0x0004
-#define TIMER_MODE          0x0003
-#define TIMER_MODE_PWM      0x0001
-#define TIMER_MODE_WDTH     0x0002
-#define TIMER_MODE_EXT_CLK  0x0003
-
-/*
-** Timer Status Register Bits
-*/
-#define TIMER_STATUS_TIMIL0 0x0001
-#define TIMER_STATUS_TIMIL1 0x0002
-#define TIMER_STATUS_TIMIL2 0x0004
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-#  define TIMER_STATUS_TIMIL3 0x00000008
-#  define TIMER_STATUS_TIMIL4 0x00010000
-#  define TIMER_STATUS_TIMIL5 0x00020000
-#  define TIMER_STATUS_TIMIL6 0x00040000
-#  define TIMER_STATUS_TIMIL7 0x00080000
-#  if (MAX_BLACKFIN_GPTIMERS > 8)
-#    define TIMER_STATUS_TIMIL8  0x0001
-#    define TIMER_STATUS_TIMIL9  0x0002
-#    define TIMER_STATUS_TIMIL10 0x0004
-#    define TIMER_STATUS_TIMIL11 0x0008
-#  endif
-#  define TIMER_STATUS_INTR   0x000F000F
-#else
-#  define TIMER_STATUS_INTR   0x0007   /* any timer interrupt */
-#endif
-
-#define TIMER_STATUS_TOVF0  0x0010     /* timer 0 overflow error */
-#define TIMER_STATUS_TOVF1  0x0020
-#define TIMER_STATUS_TOVF2  0x0040
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-#  define TIMER_STATUS_TOVF3  0x00000080
-#  define TIMER_STATUS_TOVF4  0x00100000
-#  define TIMER_STATUS_TOVF5  0x00200000
-#  define TIMER_STATUS_TOVF6  0x00400000
-#  define TIMER_STATUS_TOVF7  0x00800000
-#  if (MAX_BLACKFIN_GPTIMERS > 8)
-#    define TIMER_STATUS_TOVF8   0x0010
-#    define TIMER_STATUS_TOVF9   0x0020
-#    define TIMER_STATUS_TOVF10  0x0040
-#    define TIMER_STATUS_TOVF11  0x0080
-#  endif
-#  define TIMER_STATUS_OFLOW  0x00F000F0
-#else
-#  define TIMER_STATUS_OFLOW  0x0070   /* any timer overflow */
-#endif
-
-/*
-** Timer Slave Enable Status : write 1 to clear
-*/
-#define TIMER_STATUS_TRUN0  0x1000
-#define TIMER_STATUS_TRUN1  0x2000
-#define TIMER_STATUS_TRUN2  0x4000
-#if (MAX_BLACKFIN_GPTIMERS > 3)
-#  define TIMER_STATUS_TRUN3  0x00008000
-#  define TIMER_STATUS_TRUN4  0x10000000
-#  define TIMER_STATUS_TRUN5  0x20000000
-#  define TIMER_STATUS_TRUN6  0x40000000
-#  define TIMER_STATUS_TRUN7  0x80000000
-#  define TIMER_STATUS_TRUN   0xF000F000
-#  if (MAX_BLACKFIN_GPTIMERS > 8)
-#    define TIMER_STATUS_TRUN8  0x1000
-#    define TIMER_STATUS_TRUN9  0x2000
-#    define TIMER_STATUS_TRUN10 0x4000
-#    define TIMER_STATUS_TRUN11 0x8000
-#  endif
-#else
-#  define TIMER_STATUS_TRUN   0x7000
-#endif
-
-/*******************************************************************************
-*      GP_TIMER API's
-*******************************************************************************/
-
-void  set_gptimer_pwidth    (int timer_id, int width);
-int   get_gptimer_pwidth    (int timer_id);
-void  set_gptimer_period    (int timer_id, int period);
-int   get_gptimer_period    (int timer_id);
-int   get_gptimer_count     (int timer_id);
-short get_gptimer_intr      (int timer_id);
-void  set_gptimer_config    (int timer_id, short config);
-short get_gptimer_config    (int timer_id);
-void  set_gptimer_pulse_hi  (int timer_id);
-void  clear_gptimer_pulse_hi(int timer_id);
-void  enable_gptimers       (short mask);
-void  disable_gptimers      (short mask);
-short get_enabled_timers    (void);
-int   get_gptimer_status    (int octet);
-void  set_gptimer_status    (int octet, int value);
-
-#endif
index a970781..14cb8d3 100644 (file)
@@ -47,6 +47,8 @@
 
 extern unsigned long get_cclk(void);
 extern unsigned long get_sclk(void);
+extern unsigned long sclk_to_usecs(unsigned long sclk);
+extern unsigned long usecs_to_sclk(unsigned long usecs);
 
 extern void dump_thread(struct pt_regs *regs, struct user *dump);
 extern void dump_bfin_regs(struct pt_regs *fp, void *retaddr);
@@ -105,7 +107,7 @@ extern void led_disp_num(int);
 extern void led_toggle_num(int);
 extern void init_leds(void);
 
-extern char *bfin_board_name __attribute__ ((weak));
+extern const char bfin_board_name[];
 extern unsigned long wall_jiffies;
 extern unsigned long ipdt_table[];
 extern unsigned long dpdt_table[];
index b42a531..b469505 100644 (file)
@@ -109,9 +109,7 @@ struct dma_register {
 
        unsigned long curr_desc_ptr;    /* DMA Current Descriptor Pointer
                                           register */
-       unsigned short curr_addr_ptr_lo;        /* DMA Current Address Pointer
-                                                  register */
-       unsigned short curr_addr_ptr_hi;        /* DMA Current Address Pointer
+       unsigned long curr_addr_ptr;    /* DMA Current Address Pointer
                                                   register */
        unsigned short irq_status;      /* DMA irq status register */
        unsigned short dummy6;
@@ -166,6 +164,9 @@ void set_dma_curr_addr(unsigned int channel, unsigned long addr);
 unsigned short get_dma_curr_irqstat(unsigned int channel);
 unsigned short get_dma_curr_xcount(unsigned int channel);
 unsigned short get_dma_curr_ycount(unsigned int channel);
+unsigned long get_dma_next_desc_ptr(unsigned int channel);
+unsigned long get_dma_curr_desc_ptr(unsigned int channel);
+unsigned long get_dma_curr_addr(unsigned int channel);
 
 /* set large DMA mode descriptor */
 void set_dma_sg(unsigned int channel, struct dmasg *sg, int nr_sg);
index dd203cd..33ce98e 100644 (file)
@@ -29,6 +29,7 @@
 
 /*
 *  Number     BF537/6/4    BF561    BF533/2/1
+*             BF527/5/2
 *
 *  GPIO_0       PF0         PF0        PF0
 *  GPIO_1       PF1         PF1        PF1
 
 #endif
 
-#ifdef BF537_FAMILY
+#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
 #define MAX_BLACKFIN_GPIOS 48
 
 #define        GPIO_PF0        0
diff --git a/include/asm-blackfin/gptimers.h b/include/asm-blackfin/gptimers.h
new file mode 100644 (file)
index 0000000..c97ab03
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * include/asm/bf5xx_timers.h
+ *
+ * This file contains the major Data structures and constants
+ * used for General Purpose Timer Implementation in BF5xx
+ *
+ * Copyright (C) 2005 John DeHority
+ * Copyright (C) 2006 Hella Aglaia GmbH (awe@aglaia-gmbh.de)
+ *
+ */
+
+#ifndef _BLACKFIN_TIMERS_H_
+#define _BLACKFIN_TIMERS_H_
+
+#include <linux/types.h>
+#include <asm/blackfin.h>
+
+/*
+ * BF537/BF527: 8 timers:
+ */
+#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
+# define MAX_BLACKFIN_GPTIMERS 8
+# define TIMER0_GROUP_REG      TIMER_ENABLE
+#endif
+/*
+ * BF561: 12 timers:
+ */
+#if defined(CONFIG_BF561)
+# define MAX_BLACKFIN_GPTIMERS 12
+# define TIMER0_GROUP_REG      TMRS8_ENABLE
+# define TIMER8_GROUP_REG      TMRS4_ENABLE
+#endif
+/*
+ * All others: 3 timers:
+ */
+#if !defined(MAX_BLACKFIN_GPTIMERS)
+# define MAX_BLACKFIN_GPTIMERS 3
+# define TIMER0_GROUP_REG      TIMER_ENABLE
+#endif
+
+#define BLACKFIN_GPTIMER_IDMASK ((1UL << MAX_BLACKFIN_GPTIMERS) - 1)
+#define BFIN_TIMER_OCTET(x) ((x) >> 3)
+
+/* used in masks for timer_enable() and timer_disable() */
+#define TIMER0bit  0x0001  /*  0001b */
+#define TIMER1bit  0x0002  /*  0010b */
+#define TIMER2bit  0x0004  /*  0100b */
+
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER3bit  0x0008
+# define TIMER4bit  0x0010
+# define TIMER5bit  0x0020
+# define TIMER6bit  0x0040
+# define TIMER7bit  0x0080
+#endif
+
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+# define TIMER8bit  0x0100
+# define TIMER9bit  0x0200
+# define TIMER10bit 0x0400
+# define TIMER11bit 0x0800
+#endif
+
+#define TIMER0_id   0
+#define TIMER1_id   1
+#define TIMER2_id   2
+
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER3_id   3
+# define TIMER4_id   4
+# define TIMER5_id   5
+# define TIMER6_id   6
+# define TIMER7_id   7
+#endif
+
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+# define TIMER8_id   8
+# define TIMER9_id   9
+# define TIMER10_id 10
+# define TIMER11_id 11
+#endif
+
+/* associated timers for ppi framesync: */
+
+#if defined(CONFIG_BF561)
+# define FS0_1_TIMER_ID   TIMER8_id
+# define FS0_2_TIMER_ID   TIMER9_id
+# define FS1_1_TIMER_ID   TIMER10_id
+# define FS1_2_TIMER_ID   TIMER11_id
+# define FS0_1_TIMER_BIT  TIMER8bit
+# define FS0_2_TIMER_BIT  TIMER9bit
+# define FS1_1_TIMER_BIT  TIMER10bit
+# define FS1_2_TIMER_BIT  TIMER11bit
+# undef FS1_TIMER_ID
+# undef FS2_TIMER_ID
+# undef FS1_TIMER_BIT
+# undef FS2_TIMER_BIT
+#else
+# define FS1_TIMER_ID  TIMER0_id
+# define FS2_TIMER_ID  TIMER1_id
+# define FS1_TIMER_BIT TIMER0bit
+# define FS2_TIMER_BIT TIMER1bit
+#endif
+
+/*
+ * Timer Configuration Register Bits
+ */
+#define TIMER_ERR           0xC000
+#define TIMER_ERR_OVFL      0x4000
+#define TIMER_ERR_PROG_PER  0x8000
+#define TIMER_ERR_PROG_PW   0xC000
+#define TIMER_EMU_RUN       0x0200
+#define        TIMER_TOGGLE_HI     0x0100
+#define        TIMER_CLK_SEL       0x0080
+#define TIMER_OUT_DIS       0x0040
+#define TIMER_TIN_SEL       0x0020
+#define TIMER_IRQ_ENA       0x0010
+#define TIMER_PERIOD_CNT    0x0008
+#define TIMER_PULSE_HI      0x0004
+#define TIMER_MODE          0x0003
+#define TIMER_MODE_PWM      0x0001
+#define TIMER_MODE_WDTH     0x0002
+#define TIMER_MODE_EXT_CLK  0x0003
+
+/*
+ * Timer Status Register Bits
+ */
+#define TIMER_STATUS_TIMIL0 0x0001
+#define TIMER_STATUS_TIMIL1 0x0002
+#define TIMER_STATUS_TIMIL2 0x0004
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER_STATUS_TIMIL3 0x00000008
+# define TIMER_STATUS_TIMIL4 0x00010000
+# define TIMER_STATUS_TIMIL5 0x00020000
+# define TIMER_STATUS_TIMIL6 0x00040000
+# define TIMER_STATUS_TIMIL7 0x00080000
+# if (MAX_BLACKFIN_GPTIMERS > 8)
+#  define TIMER_STATUS_TIMIL8  0x0001
+#  define TIMER_STATUS_TIMIL9  0x0002
+#  define TIMER_STATUS_TIMIL10 0x0004
+#  define TIMER_STATUS_TIMIL11 0x0008
+# endif
+# define TIMER_STATUS_INTR   0x000F000F
+#else
+# define TIMER_STATUS_INTR   0x0007    /* any timer interrupt */
+#endif
+
+#define TIMER_STATUS_TOVF0  0x0010     /* timer 0 overflow error */
+#define TIMER_STATUS_TOVF1  0x0020
+#define TIMER_STATUS_TOVF2  0x0040
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER_STATUS_TOVF3  0x00000080
+# define TIMER_STATUS_TOVF4  0x00100000
+# define TIMER_STATUS_TOVF5  0x00200000
+# define TIMER_STATUS_TOVF6  0x00400000
+# define TIMER_STATUS_TOVF7  0x00800000
+# if (MAX_BLACKFIN_GPTIMERS > 8)
+#  define TIMER_STATUS_TOVF8   0x0010
+#  define TIMER_STATUS_TOVF9   0x0020
+#  define TIMER_STATUS_TOVF10  0x0040
+#  define TIMER_STATUS_TOVF11  0x0080
+# endif
+# define TIMER_STATUS_OFLOW  0x00F000F0
+#else
+# define TIMER_STATUS_OFLOW  0x0070    /* any timer overflow */
+#endif
+
+/*
+ * Timer Slave Enable Status : write 1 to clear
+ */
+#define TIMER_STATUS_TRUN0  0x1000
+#define TIMER_STATUS_TRUN1  0x2000
+#define TIMER_STATUS_TRUN2  0x4000
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER_STATUS_TRUN3  0x00008000
+# define TIMER_STATUS_TRUN4  0x10000000
+# define TIMER_STATUS_TRUN5  0x20000000
+# define TIMER_STATUS_TRUN6  0x40000000
+# define TIMER_STATUS_TRUN7  0x80000000
+# define TIMER_STATUS_TRUN   0xF000F000
+# if (MAX_BLACKFIN_GPTIMERS > 8)
+#  define TIMER_STATUS_TRUN8  0x1000
+#  define TIMER_STATUS_TRUN9  0x2000
+#  define TIMER_STATUS_TRUN10 0x4000
+#  define TIMER_STATUS_TRUN11 0x8000
+# endif
+#else
+# define TIMER_STATUS_TRUN   0x7000
+#endif
+
+/* The actual gptimer API */
+
+void     set_gptimer_pwidth    (int timer_id, uint32_t width);
+uint32_t get_gptimer_pwidth    (int timer_id);
+void     set_gptimer_period    (int timer_id, uint32_t period);
+uint32_t get_gptimer_period    (int timer_id);
+uint32_t get_gptimer_count     (int timer_id);
+uint16_t get_gptimer_intr      (int timer_id);
+void     clear_gptimer_intr    (int timer_id);
+void     set_gptimer_config    (int timer_id, uint16_t config);
+uint16_t get_gptimer_config    (int timer_id);
+void     set_gptimer_pulse_hi  (int timer_id);
+void     clear_gptimer_pulse_hi(int timer_id);
+void     enable_gptimers       (uint16_t mask);
+void     disable_gptimers      (uint16_t mask);
+uint16_t get_enabled_gptimers  (void);
+uint32_t get_gptimer_status    (int group);
+void     set_gptimer_status    (int group, uint32_t value);
+
+#endif
index 991db98..a891204 100644 (file)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000244 (0)
+#define ANOMALY_05000198 (0)
+#define ANOMALY_05000125 (0)
+#define ANOMALY_05000158 (0)
+#define ANOMALY_05000273 (0)
+#define ANOMALY_05000263 (0)
+#define ANOMALY_05000311 (0)
+#define ANOMALY_05000230 (0)
 #endif
diff --git a/include/asm-blackfin/mach-bf527/bf527.h b/include/asm-blackfin/mach-bf527/bf527.h
new file mode 100644 (file)
index 0000000..056eb4b
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * File:         include/asm-blackfin/mach-bf527/bf527.h
+ * Based on:   include/asm-blackfin/mach-bf537/bf537.h
+ * Author:     Michael Hennerich (michael.hennerich@analog.com)
+ *
+ * Created:
+ * Description:  SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF527
+ *
+ * Modified:
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __MACH_BF527_H__
+#define __MACH_BF527_H__
+
+#define SUPPORTED_REVID 2
+
+#define OFFSET_(x) ((x) & 0x0000FFFF)
+
+/*some misc defines*/
+#define IMASK_IVG15            0x8000
+#define IMASK_IVG14            0x4000
+#define IMASK_IVG13            0x2000
+#define IMASK_IVG12            0x1000
+
+#define IMASK_IVG11            0x0800
+#define IMASK_IVG10            0x0400
+#define IMASK_IVG9             0x0200
+#define IMASK_IVG8             0x0100
+
+#define IMASK_IVG7             0x0080
+#define IMASK_IVGTMR   0x0040
+#define IMASK_IVGHW            0x0020
+
+/***************************/
+
+#define BFIN_DSUBBANKS 4
+#define BFIN_DWAYS             2
+#define BFIN_DLINES            64
+#define BFIN_ISUBBANKS 4
+#define BFIN_IWAYS             4
+#define BFIN_ILINES            32
+
+#define WAY0_L                 0x1
+#define WAY1_L                 0x2
+#define WAY01_L                        0x3
+#define WAY2_L                 0x4
+#define WAY02_L                        0x5
+#define        WAY12_L                 0x6
+#define        WAY012_L                0x7
+
+#define        WAY3_L                  0x8
+#define        WAY03_L                 0x9
+#define        WAY13_L                 0xA
+#define        WAY013_L                0xB
+
+#define        WAY32_L                 0xC
+#define        WAY320_L                0xD
+#define        WAY321_L                0xE
+#define        WAYALL_L                0xF
+
+#define DMC_ENABLE (2<<2)      /*yes, 2, not 1 */
+
+/********************************* EBIU Settings ************************************/
+#define AMBCTL0VAL     ((CONFIG_BANK_1 << 16) | CONFIG_BANK_0)
+#define AMBCTL1VAL     ((CONFIG_BANK_3 << 16) | CONFIG_BANK_2)
+
+#ifdef CONFIG_C_AMBEN_ALL
+#define V_AMBEN AMBEN_ALL
+#endif
+#ifdef CONFIG_C_AMBEN
+#define V_AMBEN 0x0
+#endif
+#ifdef CONFIG_C_AMBEN_B0
+#define V_AMBEN AMBEN_B0
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1
+#define V_AMBEN AMBEN_B0_B1
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1_B2
+#define V_AMBEN AMBEN_B0_B1_B2
+#endif
+#ifdef CONFIG_C_AMCKEN
+#define V_AMCKEN AMCKEN
+#else
+#define V_AMCKEN 0x0
+#endif
+#ifdef CONFIG_C_CDPRIO
+#define V_CDPRIO 0x100
+#else
+#define V_CDPRIO 0x0
+#endif
+
+#define AMGCTLVAL      (V_AMBEN | V_AMCKEN | V_CDPRIO)
+
+#ifdef CONFIG_BF527
+#define CPU "BF527"
+#endif
+#ifdef CONFIG_BF525
+#define CPU "BF525"
+#endif
+#ifdef CONFIG_BF522
+#define CPU "BF522"
+#endif
+#ifndef CPU
+#define        CPU "UNKNOWN"
+#define CPUID 0x0
+#endif
+
+#endif                         /* __MACH_BF527_H__  */
diff --git a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
new file mode 100644 (file)
index 0000000..0b867e6
--- /dev/null
@@ -0,0 +1,152 @@
+#include <linux/serial.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#define NR_PORTS               2
+
+#define OFFSET_THR              0x00   /* Transmit Holding register            */
+#define OFFSET_RBR              0x00   /* Receive Buffer register              */
+#define OFFSET_DLL              0x00   /* Divisor Latch (Low-Byte)             */
+#define OFFSET_IER              0x04   /* Interrupt Enable Register            */
+#define OFFSET_DLH              0x04   /* Divisor Latch (High-Byte)            */
+#define OFFSET_IIR              0x08   /* Interrupt Identification Register    */
+#define OFFSET_LCR              0x0C   /* Line Control Register                */
+#define OFFSET_MCR              0x10   /* Modem Control Register               */
+#define OFFSET_LSR              0x14   /* Line Status Register                 */
+#define OFFSET_MSR              0x18   /* Modem Status Register                */
+#define OFFSET_SCR              0x1C   /* SCR Scratch Register                 */
+#define OFFSET_GCTL             0x24   /* Global Control Register              */
+
+#define UART_GET_CHAR(uart)     bfin_read16(((uart)->port.membase + OFFSET_RBR))
+#define UART_GET_DLL(uart)     bfin_read16(((uart)->port.membase + OFFSET_DLL))
+#define UART_GET_IER(uart)      bfin_read16(((uart)->port.membase + OFFSET_IER))
+#define UART_GET_DLH(uart)     bfin_read16(((uart)->port.membase + OFFSET_DLH))
+#define UART_GET_IIR(uart)      bfin_read16(((uart)->port.membase + OFFSET_IIR))
+#define UART_GET_LCR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LCR))
+#define UART_GET_LSR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LSR))
+#define UART_GET_GCTL(uart)     bfin_read16(((uart)->port.membase + OFFSET_GCTL))
+
+#define UART_PUT_CHAR(uart, v)   bfin_write16(((uart)->port.membase + OFFSET_THR), v)
+#define UART_PUT_DLL(uart, v)    bfin_write16(((uart)->port.membase + OFFSET_DLL), v)
+#define UART_PUT_IER(uart, v)    bfin_write16(((uart)->port.membase + OFFSET_IER), v)
+#define UART_PUT_DLH(uart, v)    bfin_write16(((uart)->port.membase + OFFSET_DLH), v)
+#define UART_PUT_LCR(uart, v)    bfin_write16(((uart)->port.membase + OFFSET_LCR), v)
+#define UART_PUT_GCTL(uart, v)   bfin_write16(((uart)->port.membase + OFFSET_GCTL), v)
+
+#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
+# define CONFIG_SERIAL_BFIN_CTSRTS
+
+# ifndef CONFIG_UART0_CTS_PIN
+#  define CONFIG_UART0_CTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART0_RTS_PIN
+#  define CONFIG_UART0_RTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART1_CTS_PIN
+#  define CONFIG_UART1_CTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART1_RTS_PIN
+#  define CONFIG_UART1_RTS_PIN -1
+# endif
+#endif
+/*
+ * The pin configuration is different from schematic
+ */
+struct bfin_serial_port {
+       struct uart_port port;
+       unsigned int old_status;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       int tx_done;
+       int tx_count;
+       struct circ_buf rx_dma_buf;
+       struct timer_list rx_dma_timer;
+       int rx_dma_nrows;
+       unsigned int tx_dma_channel;
+       unsigned int rx_dma_channel;
+       struct work_struct tx_dma_workqueue;
+#else
+       struct work_struct cts_workqueue;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+       int cts_pin;
+       int rts_pin;
+#endif
+};
+
+struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_res {
+       unsigned long uart_base_addr;
+       int uart_irq;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+       unsigned int uart_tx_dma_channel;
+       unsigned int uart_rx_dma_channel;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+       int uart_cts_pin;
+       int uart_rts_pin;
+#endif
+};
+
+struct bfin_serial_res bfin_serial_resource[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       {
+        0xFFC00400,
+        IRQ_UART0_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+        CH_UART0_TX,
+        CH_UART0_RX,
+#endif
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+        CONFIG_UART0_CTS_PIN,
+        CONFIG_UART0_RTS_PIN,
+#endif
+        },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       {
+        0xFFC02000,
+        IRQ_UART1_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+        CH_UART1_TX,
+        CH_UART1_RX,
+#endif
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+        CONFIG_UART1_CTS_PIN,
+        CONFIG_UART1_RTS_PIN,
+#endif
+        },
+#endif
+};
+
+int nr_ports = ARRAY_SIZE(bfin_serial_resource);
+
+#define DRIVER_NAME "bfin-uart"
+
+static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+{
+
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       peripheral_request(P_UART0_TX, DRIVER_NAME);
+       peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       peripheral_request(P_UART1_TX, DRIVER_NAME);
+       peripheral_request(P_UART1_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+       if (uart->cts_pin >= 0) {
+               gpio_request(uart->cts_pin, DRIVER_NAME);
+               gpio_direction_input(uart->cts_pin);
+       }
+
+       if (uart->rts_pin >= 0) {
+               gpio_request(uart->rts_pin, DRIVER_NAME);
+               gpio_direction_output(uart->rts_pin);
+       }
+#endif
+}
diff --git a/include/asm-blackfin/mach-bf527/blackfin.h b/include/asm-blackfin/mach-bf527/blackfin.h
new file mode 100644 (file)
index 0000000..1bd07e3
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * File:         include/asm-blackfin/mach-bf527/blackfin.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_BLACKFIN_H_
+#define _MACH_BLACKFIN_H_
+
+#define BF527_FAMILY
+
+#include "bf527.h"
+#include "mem_map.h"
+#include "defBF522.h"
+#include "anomaly.h"
+
+#if defined(CONFIG_BF527)
+#include "defBF527.h"
+#endif
+
+#if defined(CONFIG_BF525)
+#include "defBF525.h"
+#endif
+
+#if !defined(__ASSEMBLY__)
+#include "cdefBF522.h"
+
+#if defined(CONFIG_BF527)
+#include "cdefBF527.h"
+#endif
+
+#if defined(CONFIG_BF525)
+#include "cdefBF525.h"
+#endif
+#endif
+
+/* UART_IIR Register */
+#define STATUS(x)      ((x << 1) & 0x06)
+#define STATUS_P1      0x02
+#define STATUS_P0      0x01
+
+/* DPMC*/
+#define bfin_read_STOPCK_OFF() bfin_read_STOPCK()
+#define bfin_write_STOPCK_OFF(val) bfin_write_STOPCK(val)
+#define STOPCK_OFF STOPCK
+
+/* PLL_DIV Masks                                                                                                       */
+#define CCLK_DIV1 CSEL_DIV1    /*          CCLK = VCO / 1                                  */
+#define CCLK_DIV2 CSEL_DIV2    /*          CCLK = VCO / 2                                  */
+#define CCLK_DIV4 CSEL_DIV4    /*          CCLK = VCO / 4                                  */
+#define CCLK_DIV8 CSEL_DIV8    /*          CCLK = VCO / 8                                  */
+
+#endif
index 5f801a0..3f4de5d 100644 (file)
@@ -45,8 +45,8 @@
 #define bfin_write_PLL_STAT(val)               bfin_write16(PLL_STAT, val)
 #define bfin_read_PLL_LOCKCNT()                        bfin_read16(PLL_LOCKCNT)
 #define bfin_write_PLL_LOCKCNT(val)            bfin_write16(PLL_LOCKCNT, val)
-#define bfin_read_CHIPID()                     bfin_read16(CHIPID)
-#define bfin_write_CHIPID(val)                 bfin_write16(CHIPID, val)
+#define bfin_read_CHIPID()                     bfin_read32(CHIPID)
+#define bfin_write_CHIPID(val)                 bfin_write32(CHIPID, val)
 
 
 /* System Interrupt Controller (0xFFC00100 - 0xFFC001FF)                                                       */
@@ -59,9 +59,8 @@
 #define bfin_write_SIC_RVECT(val)              bfin_write32(SIC_RVECT, val)
 #define bfin_read_SIC_IMASK0()                 bfin_read32(SIC_IMASK0)
 #define bfin_write_SIC_IMASK0(val)             bfin_write32(SIC_IMASK0, val)
-/* legacy register name (below) provided for backwards code compatibility */
-#define bfin_read_SIC_IMASK()                  bfin_read32(SIC_IMASK)
-#define bfin_write_SIC_IMASK(val)              bfin_write32(SIC_IMASK, val)
+#define bfin_read_SIC_IMASK(x)                 bfin_read32(SIC_IMASK0 + (x << 6))
+#define bfin_write_SIC_IMASK(x, val)           bfin_write32((SIC_IMASK0 + (x << 6)), val)
 
 #define bfin_read_SIC_IAR0()                   bfin_read32(SIC_IAR0)
 #define bfin_write_SIC_IAR0(val)               bfin_write32(SIC_IAR0, val)
 
 #define bfin_read_SIC_ISR0()                   bfin_read32(SIC_ISR0)
 #define bfin_write_SIC_ISR0(val)               bfin_write32(SIC_ISR0, val)
-/* legacy register name (below) provided for backwards code compatibility */
-#define bfin_read_SIC_ISR()                    bfin_read32(SIC_ISR)
-#define bfin_write_SIC_ISR(val)                        bfin_write32(SIC_ISR, val)
+#define bfin_read_SIC_ISR(x)                   bfin_read32(SIC_ISR0 + (x << 6))
+#define bfin_write_SIC_ISR(x, val)             bfin_write32((SIC_ISR0 + (x << 6)), val)
 
 #define bfin_read_SIC_IWR0()                   bfin_read32(SIC_IWR0)
 #define bfin_write_SIC_IWR0(val)               bfin_write32(SIC_IWR0, val)
-/* legacy register name (below) provided for backwards code compatibility */
-#define bfin_read_SIC_IWR()                    bfin_read32(SIC_IWR)
-#define bfin_write_SIC_IWR(val)                        bfin_write32(SIC_IWR, val)
+#define bfin_read_SIC_IWR(x)                   bfin_read32(SIC_IWR0 + (x << 6))
+#define bfin_write_SIC_IWR(x, val)             bfin_write32((SIC_IWR0 + (x << 6)), val)
 
 /* SIC Additions to ADSP-BF52x (0xFFC0014C - 0xFFC00162) */
 
index 2be3293..82134f5 100644 (file)
 #define _DEF_BF527_H
 
 /* Include all Core registers and bit definitions */
-#include <def_LPBlackfin.h>
+#include <asm/mach-common/def_LPBlackfin.h>
 
 /* SYSTEM & MMR ADDRESS DEFINITIONS FOR ADSP-BF527 */
 
 /* Include defBF52x_base.h for the set of #defines that are common to all ADSP-BF52x processors */
-#include <defBF52x_base.h>
+#include "defBF52x_base.h"
 
 /* The following are the #defines needed by ADSP-BF527 that are not in the common header */
 /* 10/100 Ethernet Controller  (0xFFC03000 - 0xFFC031FF) */
index b1ff67d..d6c24c5 100644 (file)
 #define SYSCR                          0xFFC00104      /* System Configuration Register                        */
 #define SIC_RVECT                      0xFFC00108      /* Interrupt Reset Vector Address Register      */
 
-#define SIC_IMASK                      0xFFC0010C      /* Interrupt Mask Register                                      */
+#define SIC_IMASK0                     0xFFC0010C      /* Interrupt Mask Register                                      */
 #define SIC_IAR0                       0xFFC00110      /* Interrupt Assignment Register 0                      */
 #define SIC_IAR1                       0xFFC00114      /* Interrupt Assignment Register 1                      */
 #define SIC_IAR2                       0xFFC00118      /* Interrupt Assignment Register 2                      */
 #define SIC_IAR3                       0xFFC0011C      /* Interrupt Assignment Register 3                      */
-#define SIC_ISR                                0xFFC00120      /* Interrupt Status Register                            */
-#define SIC_IWR                                0xFFC00124      /* Interrupt Wakeup Register                            */
+#define SIC_ISR0                               0xFFC00120      /* Interrupt Status Register                            */
+#define SIC_IWR0                               0xFFC00124      /* Interrupt Wakeup Register                            */
 
 /* SIC Additions to ADSP-BF52x (0xFFC0014C - 0xFFC00162) */
 #define SIC_IMASK1                      0xFFC0014C     /* Interrupt Mask register of SIC2 */
 
 /* *************  SYSTEM INTERRUPT CONTROLLER MASKS *************************************/
 /* Peripheral Masks For SIC_ISR, SIC_IWR, SIC_IMASK                                                                            */
+
+#if 0
 #define IRQ_PLL_WAKEUP 0x00000001      /* PLL Wakeup Interrupt                                                         */
 
 #define IRQ_ERROR1      0x00000002  /* Error Interrupt (DMA, DMARx Block, DMARx Overflow) */
 #define IRQ_DMA15              0x40000000      /* DMA Channels 15 (MDMA0 Destination) TX Interrupt */
 #define IRQ_WDOG               0x80000000      /* Software Watchdog Timer Interrupt                            */
 #define IRQ_PFB_PORTG  0x10000000      /* PF Port G (PF31:16) Interrupt B                                      */
+#endif
 
 /* SIC_IAR0 Macros                                                                                                                     */
 #define P0_IVG(x)              (((x)&0xF)-7)                   /* Peripheral #0 assigned IVG #x        */
diff --git a/include/asm-blackfin/mach-bf527/dma.h b/include/asm-blackfin/mach-bf527/dma.h
new file mode 100644 (file)
index 0000000..a41627a
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * file:        include/asm-blackfin/mach-bf527/dma.h
+ * based on:   include/asm-blackfin/mach-bf537/dma.h
+ * author:     Michael Hennerich (michael.hennerich@analog.com)
+ *
+ * created:
+ * description:
+ *     system DMA map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.org/
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license as published by
+ * the free software foundation; either version 2, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _MACH_DMA_H_
+#define _MACH_DMA_H_
+
+#define MAX_BLACKFIN_DMA_CHANNEL 16
+
+#define CH_PPI                         0       /* PPI receive/transmit or NFC */
+#define CH_NFC                 0       /* PPI receive/transmit or NFC */
+#define CH_EMAC_RX             1       /* Ethernet MAC receive or HOSTDP */
+#define CH_EMAC_HOSTDP                 1       /* Ethernet MAC receive or HOSTDP */
+#define CH_EMAC_TX             2       /* Ethernet MAC transmit or NFC */
+#define CH_SPORT0_RX           3       /* SPORT0 receive */
+#define CH_SPORT0_TX           4       /* SPORT0 transmit */
+#define CH_SPORT1_RX           5       /* SPORT1 receive */
+#define CH_SPORT1_TX           6       /* SPORT1 transmit */
+#define CH_SPI                         7       /* SPI transmit/receive */
+#define CH_UART0_RX            8       /* UART0 receive */
+#define CH_UART0_TX            9       /* UART0 transmit */
+#define CH_UART1_RX            10      /* UART1 receive */
+#define CH_UART1_TX            11      /* UART1 transmit */
+
+#define CH_MEM_STREAM0_DEST    12      /* TX */
+#define CH_MEM_STREAM0_SRC     13      /* RX */
+#define CH_MEM_STREAM1_DEST    14      /* TX */
+#define CH_MEM_STREAM1_SRC     15      /* RX */
+
+extern int channel2irq(unsigned int channel);
+extern struct dma_register *base_addr[];
+
+#endif
diff --git a/include/asm-blackfin/mach-bf527/irq.h b/include/asm-blackfin/mach-bf527/irq.h
new file mode 100644 (file)
index 0000000..304f5bc
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * file:       include/asm-blackfin/mach-bf527/irq.h
+ * based on:   include/asm-blackfin/mach-bf537/irq.h
+ * author:     Michael Hennerich (michael.hennerich@analog.com)
+ *
+ * created:
+ * description:
+ *     system mmr register map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.org/
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license as published by
+ * the free software foundation; either version 2, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _BF527_IRQ_H_
+#define _BF527_IRQ_H_
+
+/*
+ * Interrupt source definitions
+       Event Source    Core Event Name
+       Core        Emulation               **
+       Events         (highest priority)  EMU         0
+       Reset                   RST         1
+       NMI                     NMI         2
+       Exception               EVX         3
+       Reserved                --          4
+       Hardware Error          IVHW        5
+       Core Timer              IVTMR       6 *
+
+       .....
+
+        Software Interrupt 1    IVG14       31
+        Software Interrupt 2    --
+        (lowest priority)  IVG15       32 *
+*/
+
+#define NR_PERI_INTS    (2 * 32)
+
+/* The ABSTRACT IRQ definitions */
+/** the first seven of the following are fixed, the rest you change if you need to **/
+#define IRQ_EMU                        0       /* Emulation */
+#define IRQ_RST                        1       /* reset */
+#define IRQ_NMI                        2       /* Non Maskable */
+#define IRQ_EVX                        3       /* Exception */
+#define IRQ_UNUSED             4       /* - unused interrupt */
+#define IRQ_HWERR              5       /* Hardware Error */
+#define IRQ_CORETMR            6       /* Core timer */
+
+#define BFIN_IRQ(x)            ((x) + 7)
+
+#define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
+#define IRQ_DMA0_ERROR         BFIN_IRQ(1)     /* DMA Error 0 (generic) */
+#define IRQ_DMAR0_BLK          BFIN_IRQ(2)     /* DMAR0 Block Interrupt */
+#define IRQ_DMAR1_BLK          BFIN_IRQ(3)     /* DMAR1 Block Interrupt */
+#define IRQ_DMAR0_OVR          BFIN_IRQ(4)     /* DMAR0 Overflow Error */
+#define IRQ_DMAR1_OVR          BFIN_IRQ(5)     /* DMAR1 Overflow Error */
+#define IRQ_PPI_ERROR          BFIN_IRQ(6)     /* PPI Error */
+#define IRQ_MAC_ERROR          BFIN_IRQ(7)     /* MAC Status */
+#define IRQ_SPORT0_ERROR       BFIN_IRQ(8)     /* SPORT0 Status */
+#define IRQ_SPORT1_ERROR       BFIN_IRQ(9)     /* SPORT1 Status */
+#define IRQ_UART0_ERROR                BFIN_IRQ(12)    /* UART0 Status */
+#define IRQ_UART1_ERROR                BFIN_IRQ(13)    /* UART1 Status */
+#define IRQ_RTC                        BFIN_IRQ(14)    /* RTC */
+#define IRQ_PPI                BFIN_IRQ(15)    /* DMA Channel 0 (PPI/NAND) */
+#define IRQ_SPORT0_RX          BFIN_IRQ(16)    /* DMA 3 Channel (SPORT0 RX) */
+#define IRQ_SPORT0_TX          BFIN_IRQ(17)    /* DMA 4 Channel (SPORT0 TX) */
+#define IRQ_SPORT1_RX          BFIN_IRQ(18)    /* DMA 5 Channel (SPORT1 RX) */
+#define IRQ_SPORT1_TX          BFIN_IRQ(19)    /* DMA 6 Channel (SPORT1 TX) */
+#define IRQ_TWI                BFIN_IRQ(20)    /* TWI */
+#define IRQ_SPI                BFIN_IRQ(21)    /* DMA 7 Channel (SPI) */
+#define IRQ_UART0_RX           BFIN_IRQ(22)    /* DMA8 Channel (UART0 RX) */
+#define IRQ_UART0_TX           BFIN_IRQ(23)    /* DMA9 Channel (UART0 TX) */
+#define IRQ_UART1_RX           BFIN_IRQ(24)    /* DMA10 Channel (UART1 RX) */
+#define IRQ_UART1_TX           BFIN_IRQ(25)    /* DMA11 Channel (UART1 TX) */
+#define IRQ_OPTSEC             BFIN_IRQ(26)    /* OTPSEC Interrupt */
+#define IRQ_CNT                BFIN_IRQ(27)    /* GP Counter */
+#define IRQ_MAC_RX             BFIN_IRQ(28)    /* DMA1 Channel (MAC RX/HDMA) */
+#define IRQ_PORTH_INTA         BFIN_IRQ(29)    /* Port H Interrupt A */
+#define IRQ_MAC_TX             BFIN_IRQ(30)    /* DMA2 Channel (MAC TX/NAND) */
+#define IRQ_NFC                        BFIN_IRQ(30)    /* DMA2 Channel (MAC TX/NAND) */
+#define IRQ_PORTH_INTB         BFIN_IRQ(31)    /* Port H Interrupt B */
+#define IRQ_TMR0               BFIN_IRQ(32)    /* Timer 0 */
+#define IRQ_TMR1               BFIN_IRQ(33)    /* Timer 1 */
+#define IRQ_TMR2               BFIN_IRQ(34)    /* Timer 2 */
+#define IRQ_TMR3               BFIN_IRQ(35)    /* Timer 3 */
+#define IRQ_TMR4               BFIN_IRQ(36)    /* Timer 4 */
+#define IRQ_TMR5               BFIN_IRQ(37)    /* Timer 5 */
+#define IRQ_TMR6               BFIN_IRQ(38)    /* Timer 6 */
+#define IRQ_TMR7               BFIN_IRQ(39)    /* Timer 7 */
+#define IRQ_PORTG_INTA         BFIN_IRQ(40)    /* Port G Interrupt A */
+#define IRQ_PORTG_INTB         BFIN_IRQ(41)    /* Port G Interrupt B */
+#define IRQ_MEM_DMA0           BFIN_IRQ(42)    /* MDMA Stream 0 */
+#define IRQ_MEM_DMA1           BFIN_IRQ(43)    /* MDMA Stream 1 */
+#define IRQ_WATCH              BFIN_IRQ(44)    /* Software Watchdog Timer */
+#define IRQ_PORTF_INTA         BFIN_IRQ(45)    /* Port F Interrupt A */
+#define IRQ_PORTF_INTB         BFIN_IRQ(46)    /* Port F Interrupt B */
+#define IRQ_SPI_ERROR          BFIN_IRQ(47)    /* SPI Status */
+#define IRQ_NFC_ERROR          BFIN_IRQ(48)    /* NAND Error */
+#define IRQ_HDMA_ERROR         BFIN_IRQ(49)    /* HDMA Error */
+#define IRQ_HDMA               BFIN_IRQ(50)    /* HDMA (TFI) */
+#define IRQ_USB_EINT           BFIN_IRQ(51)    /* USB_EINT Interrupt */
+#define IRQ_USB_INT0           BFIN_IRQ(52)    /* USB_INT0 Interrupt */
+#define IRQ_USB_INT1           BFIN_IRQ(53)    /* USB_INT1 Interrupt */
+#define IRQ_USB_INT2           BFIN_IRQ(54)    /* USB_INT2 Interrupt */
+#define IRQ_USB_DMA            BFIN_IRQ(55)    /* USB_DMAINT Interrupt */
+
+#define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
+
+#define IRQ_PF0         71
+#define IRQ_PF1         72
+#define IRQ_PF2         73
+#define IRQ_PF3         74
+#define IRQ_PF4         75
+#define IRQ_PF5         76
+#define IRQ_PF6         77
+#define IRQ_PF7         78
+#define IRQ_PF8         79
+#define IRQ_PF9         80
+#define IRQ_PF10        81
+#define IRQ_PF11        82
+#define IRQ_PF12        83
+#define IRQ_PF13        84
+#define IRQ_PF14        85
+#define IRQ_PF15        86
+
+#define IRQ_PG0         87
+#define IRQ_PG1         88
+#define IRQ_PG2         89
+#define IRQ_PG3         90
+#define IRQ_PG4         91
+#define IRQ_PG5         92
+#define IRQ_PG6         93
+#define IRQ_PG7         94
+#define IRQ_PG8         95
+#define IRQ_PG9         96
+#define IRQ_PG10        97
+#define IRQ_PG11        98
+#define IRQ_PG12        99
+#define IRQ_PG13        100
+#define IRQ_PG14        101
+#define IRQ_PG15        102
+
+#define IRQ_PH0         103
+#define IRQ_PH1         104
+#define IRQ_PH2         105
+#define IRQ_PH3         106
+#define IRQ_PH4         107
+#define IRQ_PH5         108
+#define IRQ_PH6         109
+#define IRQ_PH7         110
+#define IRQ_PH8         111
+#define IRQ_PH9         112
+#define IRQ_PH10        113
+#define IRQ_PH11        114
+#define IRQ_PH12        115
+#define IRQ_PH13        116
+#define IRQ_PH14        117
+#define IRQ_PH15        118
+
+#define GPIO_IRQ_BASE  IRQ_PF0
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#define NR_IRQS     (IRQ_PH15+1)
+#else
+#define NR_IRQS     (SYS_IRQS+1)
+#endif
+
+#define IVG7            7
+#define IVG8            8
+#define IVG9            9
+#define IVG10           10
+#define IVG11           11
+#define IVG12           12
+#define IVG13           13
+#define IVG14           14
+#define IVG15           15
+
+/* IAR0 BIT FIELDS */
+#define IRQ_PLL_WAKEUP_POS     0
+#define IRQ_DMA0_ERROR_POS     4
+#define IRQ_DMAR0_BLK_POS      8
+#define IRQ_DMAR1_BLK_POS      12
+#define IRQ_DMAR0_OVR_POS      16
+#define IRQ_DMAR1_OVR_POS      20
+#define IRQ_PPI_ERROR_POS      24
+#define IRQ_MAC_ERROR_POS      28
+
+/* IAR1 BIT FIELDS */
+#define IRQ_SPORT0_ERROR_POS   0
+#define IRQ_SPORT1_ERROR_POS   4
+#define IRQ_UART0_ERROR_POS    16
+#define IRQ_UART1_ERROR_POS    20
+#define IRQ_RTC_POS            24
+#define IRQ_PPI_POS            28
+
+/* IAR2 BIT FIELDS */
+#define IRQ_SPORT0_RX_POS      0
+#define IRQ_SPORT0_TX_POS      4
+#define IRQ_SPORT1_RX_POS      8
+#define IRQ_SPORT1_TX_POS      12
+#define IRQ_TWI_POS            16
+#define IRQ_SPI_POS            20
+#define IRQ_UART0_RX_POS       24
+#define IRQ_UART0_TX_POS       28
+
+/* IAR3 BIT FIELDS */
+#define IRQ_UART1_RX_POS       0
+#define IRQ_UART1_TX_POS       4
+#define IRQ_OPTSEC_POS         8
+#define IRQ_CNT_POS            12
+#define IRQ_MAC_RX_POS         16
+#define IRQ_PORTH_INTA_POS     20
+#define IRQ_MAC_TX_POS         24
+#define IRQ_PORTH_INTB_POS     28
+
+/* IAR4 BIT FIELDS */
+#define IRQ_TMR0_POS           0
+#define IRQ_TMR1_POS           4
+#define IRQ_TMR2_POS           8
+#define IRQ_TMR3_POS           12
+#define IRQ_TMR4_POS           16
+#define IRQ_TMR5_POS           20
+#define IRQ_TMR6_POS           24
+#define IRQ_TMR7_POS           28
+
+/* IAR5 BIT FIELDS */
+#define IRQ_PORTG_INTA_POS     0
+#define IRQ_PORTG_INTB_POS     4
+#define IRQ_MEM_DMA0_POS       8
+#define IRQ_MEM_DMA1_POS       12
+#define IRQ_WATCH_POS          16
+#define IRQ_PORTF_INTA_POS     20
+#define IRQ_PORTF_INTB_POS     24
+#define IRQ_SPI_ERROR_POS      28
+
+/* IAR6 BIT FIELDS */
+#define IRQ_NFC_ERROR_POS      0
+#define IRQ_HDMA_ERROR_POS     4
+#define IRQ_HDMA_POS           8
+#define IRQ_USB_EINT_POS       12
+#define IRQ_USB_INT0_POS       16
+#define IRQ_USB_INT1_POS       20
+#define IRQ_USB_INT2_POS       24
+#define IRQ_USB_DMA_POS        28
+
+#endif                         /* _BF527_IRQ_H_ */
diff --git a/include/asm-blackfin/mach-bf527/mem_init.h b/include/asm-blackfin/mach-bf527/mem_init.h
new file mode 100644 (file)
index 0000000..008ca66
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * File:         include/asm-blackfin/mach-bf527/mem_init.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75 || CONFIG_MEM_MT48LC64M4A2FB_7E || CONFIG_MEM_MT48LC16M8A2TG_75 || CONFIG_MEM_GENERIC_BOARD || CONFIG_MEM_MT48LC32M8A2_75 || CONFIG_MEM_MT48LC32M16A2TG_75)
+#if (CONFIG_SCLK_HZ > 119402985)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_7
+#define SDRAM_tRAS_num  7
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 104477612) && (CONFIG_SCLK_HZ <= 119402985)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_6
+#define SDRAM_tRAS_num  6
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 89552239) && (CONFIG_SCLK_HZ <= 104477612)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_5
+#define SDRAM_tRAS_num  5
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 74626866) && (CONFIG_SCLK_HZ <= 89552239)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_4
+#define SDRAM_tRAS_num  4
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 66666667) && (CONFIG_SCLK_HZ <= 74626866)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_3
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 59701493) && (CONFIG_SCLK_HZ <= 66666667)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_4
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 44776119) && (CONFIG_SCLK_HZ <= 59701493)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_3
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 29850746) && (CONFIG_SCLK_HZ <= 44776119)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_2
+#define SDRAM_tRAS_num  2
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ <= 29850746)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_1
+#define SDRAM_tRAS_num  1
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#endif
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64         /* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192       /* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC16M8A2TG_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64         /* Refresh period in milliseconds   */
+#define SDRAM_NRA   4096       /* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC32M8A2_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64         /* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192       /* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC64M4A2FB_7E)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64         /* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192       /* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_GENERIC_BOARD)
+  /*SDRAM INFORMATION: Modify this for your board */
+#define SDRAM_Tref  64         /* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192       /* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC32M16A2TG_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64         /* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192       /* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_SIZE == 128)
+#define SDRAM_SIZE      EBSZ_128
+#endif
+#if (CONFIG_MEM_SIZE == 64)
+#define SDRAM_SIZE      EBSZ_64
+#endif
+#if (CONFIG_MEM_SIZE == 32)
+#define SDRAM_SIZE      EBSZ_32
+#endif
+#if (CONFIG_MEM_SIZE == 16)
+#define SDRAM_SIZE      EBSZ_16
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 11)
+#define SDRAM_WIDTH     EBCAW_11
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 10)
+#define SDRAM_WIDTH     EBCAW_10
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 9)
+#define SDRAM_WIDTH     EBCAW_9
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 8)
+#define SDRAM_WIDTH     EBCAW_8
+#endif
+
+#define mem_SDBCTL      (SDRAM_WIDTH | SDRAM_SIZE | EBE)
+
+/* Equation from section 17 (p17-46) of BF533 HRM */
+#define mem_SDRRC       (((CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num)
+
+/* Enable SCLK Out */
+#define mem_SDGCTL        (SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR | PSS)
+
+#if defined CONFIG_CLKIN_HALF
+#define CLKIN_HALF       1
+#else
+#define CLKIN_HALF       0
+#endif
+
+#if defined CONFIG_PLL_BYPASS
+#define PLL_BYPASS      1
+#else
+#define PLL_BYPASS       0
+#endif
+
+/***************************************Currently Not Being Used *********************************/
+#define flash_EBIU_AMBCTL_WAT  ((CONFIG_FLASH_SPEED_BWAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_RAT  ((CONFIG_FLASH_SPEED_BRAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_HT   ((CONFIG_FLASH_SPEED_BHT  * 4) / (4000000000 / CONFIG_SCLK_HZ))
+#define flash_EBIU_AMBCTL_ST   ((CONFIG_FLASH_SPEED_BST  * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_TT   ((CONFIG_FLASH_SPEED_BTT  * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+
+#if (flash_EBIU_AMBCTL_TT > 3)
+#define flash_EBIU_AMBCTL0_TT   B0TT_4
+#endif
+#if (flash_EBIU_AMBCTL_TT == 3)
+#define flash_EBIU_AMBCTL0_TT   B0TT_3
+#endif
+#if (flash_EBIU_AMBCTL_TT == 2)
+#define flash_EBIU_AMBCTL0_TT   B0TT_2
+#endif
+#if (flash_EBIU_AMBCTL_TT < 2)
+#define flash_EBIU_AMBCTL0_TT   B0TT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_ST > 3)
+#define flash_EBIU_AMBCTL0_ST   B0ST_4
+#endif
+#if (flash_EBIU_AMBCTL_ST == 3)
+#define flash_EBIU_AMBCTL0_ST   B0ST_3
+#endif
+#if (flash_EBIU_AMBCTL_ST == 2)
+#define flash_EBIU_AMBCTL0_ST   B0ST_2
+#endif
+#if (flash_EBIU_AMBCTL_ST < 2)
+#define flash_EBIU_AMBCTL0_ST   B0ST_1
+#endif
+
+#if (flash_EBIU_AMBCTL_HT > 2)
+#define flash_EBIU_AMBCTL0_HT   B0HT_3
+#endif
+#if (flash_EBIU_AMBCTL_HT == 2)
+#define flash_EBIU_AMBCTL0_HT   B0HT_2
+#endif
+#if (flash_EBIU_AMBCTL_HT == 1)
+#define flash_EBIU_AMBCTL0_HT   B0HT_1
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT == 0)
+#define flash_EBIU_AMBCTL0_HT   B0HT_0
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT != 0)
+#define flash_EBIU_AMBCTL0_HT   B0HT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_WAT > 14)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_15
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 14)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_14
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 13)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_13
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 12)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_12
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 11)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_11
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 10)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_10
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 9)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_9
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 8)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_8
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 7)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_7
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 6)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_6
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 5)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_5
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 4)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_4
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 3)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_3
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 2)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_2
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 1)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_RAT > 14)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_15
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 14)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_14
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 13)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_13
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 12)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_12
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 11)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_11
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 10)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_10
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 9)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_9
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 8)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_8
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 7)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_7
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 6)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_6
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 5)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_5
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 4)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_4
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 3)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_3
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 2)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_2
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 1)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_1
+#endif
+
+#define flash_EBIU_AMBCTL0  \
+       (flash_EBIU_AMBCTL0_WAT | flash_EBIU_AMBCTL0_RAT | flash_EBIU_AMBCTL0_HT | \
+        flash_EBIU_AMBCTL0_ST | flash_EBIU_AMBCTL0_TT | CONFIG_FLASH_SPEED_RDYEN)
diff --git a/include/asm-blackfin/mach-bf527/mem_map.h b/include/asm-blackfin/mach-bf527/mem_map.h
new file mode 100644 (file)
index 0000000..c5aa201
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * file:         include/asm-blackfin/mach-bf527/mem_map.h
+ * based on:   include/asm-blackfin/mach-bf537/mem_map.h
+ * author:     Michael Hennerich (michael.hennerich@analog.com)
+ *
+ * created:
+ * description:
+ *     Memory MAP Common header file for blackfin BF527/5/2 of processors.
+ * rev:
+ *
+ * modified:
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.org/
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license as published by
+ * the free software foundation; either version 2, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _MEM_MAP_527_H_
+#define _MEM_MAP_527_H_
+
+#define COREMMR_BASE           0xFFE00000      /* Core MMRs */
+#define SYSMMR_BASE            0xFFC00000      /* System MMRs */
+
+/* Async Memory Banks */
+#define ASYNC_BANK3_BASE       0x20300000      /* Async Bank 3 */
+#define ASYNC_BANK3_SIZE       0x00100000      /* 1M */
+#define ASYNC_BANK2_BASE       0x20200000      /* Async Bank 2 */
+#define ASYNC_BANK2_SIZE       0x00100000      /* 1M */
+#define ASYNC_BANK1_BASE       0x20100000      /* Async Bank 1 */
+#define ASYNC_BANK1_SIZE       0x00100000      /* 1M */
+#define ASYNC_BANK0_BASE       0x20000000      /* Async Bank 0 */
+#define ASYNC_BANK0_SIZE       0x00100000      /* 1M */
+
+/* Boot ROM Memory */
+
+#define BOOT_ROM_START         0xEF000000
+
+/* Level 1 Memory */
+
+/* Memory Map for ADSP-BF527 ADSP-BF525 ADSP-BF522 processors */
+
+#ifdef CONFIG_BFIN_ICACHE
+#define BFIN_ICACHESIZE        (16*1024)
+#else
+#define BFIN_ICACHESIZE        (0*1024)
+#endif
+
+#define L1_CODE_START       0xFFA00000
+#define L1_DATA_A_START     0xFF800000
+#define L1_DATA_B_START     0xFF900000
+
+#define L1_CODE_LENGTH      0xC000
+
+#ifdef CONFIG_BFIN_DCACHE
+
+#ifdef CONFIG_BFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      0x8000
+#define BFIN_DCACHESIZE        (16*1024)
+#define BFIN_DSUPBANKS 1
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      (0x8000 - 0x4000)
+#define BFIN_DCACHESIZE        (32*1024)
+#define BFIN_DSUPBANKS 2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      0x8000
+#define L1_DATA_B_LENGTH      0x8000
+#define BFIN_DCACHESIZE        (0*1024)
+#define BFIN_DSUPBANKS 0
+#endif                         /*CONFIG_BFIN_DCACHE */
+
+/* Scratch Pad Memory */
+
+#if defined(CONFIG_BF527) || defined(CONFIG_BF536) || defined(CONFIG_BF534)
+#define L1_SCRATCH_START       0xFFB00000
+#define L1_SCRATCH_LENGTH      0x1000
+#endif
+
+#endif                         /* _MEM_MAP_527_H_ */
diff --git a/include/asm-blackfin/mach-bf527/portmux.h b/include/asm-blackfin/mach-bf527/portmux.h
new file mode 100644 (file)
index 0000000..dcf001a
--- /dev/null
@@ -0,0 +1,205 @@
+#ifndef _MACH_PORTMUX_H_
+#define _MACH_PORTMUX_H_
+
+#define P_PPI0_D0      (P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(0))
+#define P_PPI0_D1      (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(0))
+#define P_PPI0_D2      (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(0))
+#define P_PPI0_D3      (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(0))
+#define P_PPI0_D4      (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(0))
+#define P_PPI0_D5      (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(0))
+#define P_PPI0_D6      (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(0))
+#define P_PPI0_D7      (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(0))
+#define P_PPI0_D8      (P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(0))
+#define P_PPI0_D9      (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(0))
+#define P_PPI0_D10     (P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(0))
+#define P_PPI0_D11     (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(0))
+#define P_PPI0_D12     (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(0))
+#define P_PPI0_D13     (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(0))
+#define P_PPI0_D14     (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(0))
+#define P_PPI0_D15     (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(0))
+
+#if defined(CONFIG_BF527_SPORT0_PORTF)
+#define P_SPORT0_DRPRI (P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(1))
+#define P_SPORT0_RFS   (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(1))
+#define P_SPORT0_RSCLK (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(1))
+#define P_SPORT0_DTPRI (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(1))
+#define P_SPORT0_TFS   (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(1))
+#define P_SPORT0_TSCLK (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(1))
+#define P_SPORT0_DTSEC (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(1))
+#define P_SPORT0_DRSEC (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(1))
+#elif defined(CONFIG_BF527_SPORT0_PORTG)
+#define P_SPORT0_DTPRI (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(0))
+#define P_SPORT0_DRSEC (P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(1))
+#define P_SPORT0_DTSEC (P_DEFINED | P_IDENT(GPIO_PG4) | P_FUNCT(1))
+#define P_SPORT0_DRPRI (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(1))
+#define P_SPORT0_RFS   (P_DEFINED | P_IDENT(GPIO_PG8) | P_FUNCT(1))
+#define P_SPORT0_RSCLK (P_DEFINED | P_IDENT(GPIO_PG9) | P_FUNCT(1))
+#if defined(CONFIG_BF527_SPORT0_TSCLK_PG10)
+#define P_SPORT0_TSCLK (P_DEFINED | P_IDENT(GPIO_PG10) | P_FUNCT(1))
+#elif defined(CONFIG_BF527_SPORT0_TSCLK_PG14)
+#define P_SPORT0_TSCLK (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(0))
+#endif
+#define P_SPORT0_TFS   (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(0))
+#endif
+
+#define P_SPORT1_DRPRI (P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(1))
+#define P_SPORT1_RSCLK (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(1))
+#define P_SPORT1_RFS   (P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(1))
+#define P_SPORT1_TFS   (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(1))
+#define P_SPORT1_DTPRI (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(1))
+#define P_SPORT1_TSCLK (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(1))
+#define P_SPORT1_DTSEC (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(1))
+#define P_SPORT1_DRSEC (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(1))
+
+#define P_SPI0_SSEL6   (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(2))
+#define P_SPI0_SSEL7   (P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(2))
+
+#define P_SPI0_SSEL2   (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(2))
+#define P_SPI0_SSEL3   (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(2))
+
+#if defined(CONFIG_BF527_UART1_PORTF)
+#define P_UART1_TX     (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(2))
+#define P_UART1_RX     (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(2))
+#elif defined(CONFIG_BF527_UART1_PORTG)
+#define P_UART1_TX     (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(1))
+#define P_UART1_RX     (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(1))
+#endif
+
+#define P_HWAIT                (P_DONTCARE)
+
+#define P_SPI0_SS      (P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(0))
+#define P_SPI0_SSEL1   (P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(2))
+#define P_SPI0_SCK     (P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(2))
+#define P_SPI0_MISO    (P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(2))
+#define P_SPI0_MOSI    (P_DEFINED | P_IDENT(GPIO_PG4) | P_FUNCT(2))
+#define P_TMR1         (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(0))
+#define P_PPI0_FS2     (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(0))
+#define P_TMR3         (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(0))
+#define P_TMR4         (P_DEFINED | P_IDENT(GPIO_PG8) | P_FUNCT(0))
+#define P_TMR5         (P_DEFINED | P_IDENT(GPIO_PG9) | P_FUNCT(0))
+#define P_TMR6         (P_DEFINED | P_IDENT(GPIO_PG10) | P_FUNCT(0))
+/* #define P_TMR7              (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(0)) */
+#define P_DMAR1                (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(0))
+#define P_DMAR0                (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(0))
+#define P_TMR2         (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(1))
+#define P_TMR7         (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(1))
+#define P_MDC          (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(1))
+#define P_RMII0_MDINT  (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(1))
+#define P_MII0_PHYINT  (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(1))
+
+#define P_PPI0_FS3     (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(2))
+#define P_UART0_TX     (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(2))
+#define P_UART0_RX     (P_DEFINED | P_IDENT(GPIO_PG8) | P_FUNCT(2))
+
+#define P_HOST_WR      (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(2))
+#define P_HOST_ACK     (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(2))
+#define P_HOST_ADDR    (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(2))
+#define P_HOST_RD      (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(2))
+#define P_HOST_CE      (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(2))
+
+#if defined(CONFIG_BF527_NAND_D_PORTF)
+#define P_NAND_D0      (P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(2))
+#define P_NAND_D1      (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(2))
+#define P_NAND_D2      (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(2))
+#define P_NAND_D3      (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(2))
+#define P_NAND_D4      (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(2))
+#define P_NAND_D5      (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(2))
+#define P_NAND_D6      (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(2))
+#define P_NAND_D7      (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(2))
+#elif defined(CONFIG_BF527_NAND_D_PORTH)
+#define P_NAND_D0      (P_DEFINED | P_IDENT(GPIO_PH0) | P_FUNCT(0))
+#define P_NAND_D1      (P_DEFINED | P_IDENT(GPIO_PH1) | P_FUNCT(0))
+#define P_NAND_D2      (P_DEFINED | P_IDENT(GPIO_PH2) | P_FUNCT(0))
+#define P_NAND_D3      (P_DEFINED | P_IDENT(GPIO_PH3) | P_FUNCT(0))
+#define P_NAND_D4      (P_DEFINED | P_IDENT(GPIO_PH4) | P_FUNCT(0))
+#define P_NAND_D5      (P_DEFINED | P_IDENT(GPIO_PH5) | P_FUNCT(0))
+#define P_NAND_D6      (P_DEFINED | P_IDENT(GPIO_PH6) | P_FUNCT(0))
+#define P_NAND_D7      (P_DEFINED | P_IDENT(GPIO_PH7) | P_FUNCT(0))
+#endif
+
+#define P_SPI0_SSEL4   (P_DEFINED | P_IDENT(GPIO_PH8) | P_FUNCT(0))
+#define P_SPI0_SSEL5   (P_DEFINED | P_IDENT(GPIO_PH9) | P_FUNCT(0))
+#define P_NAND_CE      (P_DEFINED | P_IDENT(GPIO_PH10) | P_FUNCT(0))
+#define P_NAND_WE      (P_DEFINED | P_IDENT(GPIO_PH11) | P_FUNCT(0))
+#define P_NAND_RE      (P_DEFINED | P_IDENT(GPIO_PH12) | P_FUNCT(0))
+#define P_NAND_RB      (P_DEFINED | P_IDENT(GPIO_PH13) | P_FUNCT(0))
+#define P_NAND_CLE     (P_DEFINED | P_IDENT(GPIO_PH14) | P_FUNCT(0))
+#define P_NAND_ALE     (P_DEFINED | P_IDENT(GPIO_PH15) | P_FUNCT(0))
+
+#define P_HOST_D0      (P_DEFINED | P_IDENT(GPIO_PH0) | P_FUNCT(2))
+#define P_HOST_D1      (P_DEFINED | P_IDENT(GPIO_PH1) | P_FUNCT(2))
+#define P_HOST_D2      (P_DEFINED | P_IDENT(GPIO_PH2) | P_FUNCT(2))
+#define P_HOST_D3      (P_DEFINED | P_IDENT(GPIO_PH3) | P_FUNCT(2))
+#define P_HOST_D4      (P_DEFINED | P_IDENT(GPIO_PH4) | P_FUNCT(2))
+#define P_HOST_D5      (P_DEFINED | P_IDENT(GPIO_PH5) | P_FUNCT(2))
+#define P_HOST_D6      (P_DEFINED | P_IDENT(GPIO_PH6) | P_FUNCT(2))
+#define P_HOST_D7      (P_DEFINED | P_IDENT(GPIO_PH7) | P_FUNCT(2))
+#define P_HOST_D8      (P_DEFINED | P_IDENT(GPIO_PH8) | P_FUNCT(2))
+#define P_HOST_D9      (P_DEFINED | P_IDENT(GPIO_PH9) | P_FUNCT(2))
+#define P_HOST_D10     (P_DEFINED | P_IDENT(GPIO_PH10) | P_FUNCT(2))
+#define P_HOST_D11     (P_DEFINED | P_IDENT(GPIO_PH11) | P_FUNCT(2))
+#define P_HOST_D12     (P_DEFINED | P_IDENT(GPIO_PH12) | P_FUNCT(2))
+#define P_HOST_D13     (P_DEFINED | P_IDENT(GPIO_PH13) | P_FUNCT(2))
+#define P_HOST_D14     (P_DEFINED | P_IDENT(GPIO_PH14) | P_FUNCT(2))
+#define P_HOST_D15     (P_DEFINED | P_IDENT(GPIO_PH15) | P_FUNCT(2))
+
+#define P_MII0_ETxD0   (P_DEFINED | P_IDENT(GPIO_PH5) | P_FUNCT(1))
+#define P_MII0_ETxD1   (P_DEFINED | P_IDENT(GPIO_PH7) | P_FUNCT(1))
+#define P_MII0_ETxD2   (P_DEFINED | P_IDENT(GPIO_PH9) | P_FUNCT(1))
+#define P_MII0_ETxD3   (P_DEFINED | P_IDENT(GPIO_PH11) | P_FUNCT(1))
+#define P_MII0_ETxEN   (P_DEFINED | P_IDENT(GPIO_PH3) | P_FUNCT(1))
+#define P_MII0_TxCLK   (P_DEFINED | P_IDENT(GPIO_PH4) | P_FUNCT(1))
+#define P_MII0_COL     (P_DEFINED | P_IDENT(GPIO_PH15) | P_FUNCT(1))
+#define P_MII0_ERxD0   (P_DEFINED | P_IDENT(GPIO_PH6) | P_FUNCT(1))
+#define P_MII0_ERxD1   (P_DEFINED | P_IDENT(GPIO_PH8) | P_FUNCT(1))
+#define P_MII0_ERxD2   (P_DEFINED | P_IDENT(GPIO_PH10) | P_FUNCT(1))
+#define P_MII0_ERxD3   (P_DEFINED | P_IDENT(GPIO_PH12) | P_FUNCT(1))
+#define P_MII0_ERxDV   (P_DEFINED | P_IDENT(GPIO_PH14) | P_FUNCT(1))
+#define P_MII0_ERxCLK  (P_DEFINED | P_IDENT(GPIO_PH13) | P_FUNCT(1))
+#define P_MII0_ERxER   (P_DEFINED | P_IDENT(GPIO_PH1) | P_FUNCT(1))
+#define P_MII0_CRS     (P_DEFINED | P_IDENT(GPIO_PH0) | P_FUNCT(1))
+#define P_RMII0_REF_CLK        (P_DEFINED | P_IDENT(GPIO_PH4) | P_FUNCT(1))
+#define P_RMII0_CRS_DV (P_DEFINED | P_IDENT(GPIO_PH0) | P_FUNCT(1))
+#define P_MDIO         (P_DEFINED | P_IDENT(GPIO_PH2) | P_FUNCT(1))
+
+#define P_TWI0_SCL     (P_DONTCARE)
+#define P_TWI0_SDA     (P_DONTCARE)
+#define P_PPI0_FS1     (P_DONTCARE)
+#define P_TMR0         (P_DONTCARE)
+#define P_TMRCLK       (P_DONTCARE)
+#define P_PPI0_CLK     (P_DONTCARE)
+
+#define P_MII0 {\
+       P_MII0_ETxD0, \
+       P_MII0_ETxD1, \
+       P_MII0_ETxD2, \
+       P_MII0_ETxD3, \
+       P_MII0_ETxEN, \
+       P_MII0_TxCLK, \
+       P_MII0_PHYINT, \
+       P_MII0_COL, \
+       P_MII0_ERxD0, \
+       P_MII0_ERxD1, \
+       P_MII0_ERxD2, \
+       P_MII0_ERxD3, \
+       P_MII0_ERxDV, \
+       P_MII0_ERxCLK, \
+       P_MII0_ERxER, \
+       P_MII0_CRS, \
+       P_MDC, \
+       P_MDIO, 0}
+
+#define P_RMII0 {\
+       P_MII0_ETxD0, \
+       P_MII0_ETxD1, \
+       P_MII0_ETxEN, \
+       P_MII0_ERxD0, \
+       P_MII0_ERxD1, \
+       P_MII0_ERxER, \
+       P_RMII0_REF_CLK, \
+       P_RMII0_MDINT, \
+       P_RMII0_CRS_DV, \
+       P_MDC, \
+       P_MDIO, 0}
+
+#endif                         /* _MACH_PORTMUX_H_ */
index 50b3fe5..4e46d65 100644 (file)
 
 /* Bit masks for HOST_STATUS */
 
-#define                     READY  0x1        /* DMA Ready */
+#define                 DMA_READY  0x1        /* DMA Ready */
 #define                  FIFOFULL  0x2        /* FIFO Full */
 #define                 FIFOEMPTY  0x4        /* FIFO Empty */
 #define              DMA_COMPLETE  0x8        /* DMA Complete */
index e2632db..1d365c8 100644 (file)
 /* Debug/MP/Emulation Registers (0xFFC00014 - 0xFFC00014) */
 
 #define                           CHIPID  0xffc00014
+/* CHIPID Masks */
+#define                   CHIPID_VERSION  0xF0000000
+#define                    CHIPID_FAMILY  0x0FFFF000
+#define               CHIPID_MANUFACTURE  0x00000FFE
 
 /* System Reset and Interrupt Controller (0xFFC00100 - 0xFFC00104) */
 
 
 #define                       MFD  0xf000     /* Multi channel Frame Delay */
 #define                      FSDR  0x80       /* Frame Sync to Data Relationship */
-#define                     MCMEM  0x10       /* Multi channel Frame Mode Enable */
+#define                  MCMEN  0x10       /* Multi channel Frame Mode Enable */
 #define                   MCDRXPE  0x8        /* Multi channel DMA Receive Packing */
 #define                   MCDTXPE  0x4        /* Multi channel DMA Transmit Packing */
 #define                     MCCRM  0x3        /* 2X Clock Recovery Mode */
index 14cb10c..4d97d3a 100644 (file)
@@ -70,5 +70,5 @@
 #define MAX_BLACKFIN_DMA_CHANNEL 32
 
 extern int channel2irq(unsigned int channel);
-extern struct dma_register *base_addr[];
+extern struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL];
 #endif
index 60e07b9..04f4487 100644 (file)
@@ -4,7 +4,10 @@
 #include <linux/mm.h>
 
 struct scatterlist {
-       struct page *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long sg_magic;
+#endif
+       unsigned long page_link;
        unsigned int offset;
        dma_addr_t dma_address;
        unsigned int length;
@@ -17,7 +20,6 @@ struct scatterlist {
  * returns, or alternatively stop on the first sg_dma_len(sg) which
  * is 0.
  */
-#define sg_address(sg) (page_address((sg)->page) + (sg)->offset)
 #define sg_dma_address(sg)      ((sg)->dma_address)
 #define sg_dma_len(sg)          ((sg)->length)
 
index 4bdc44c..faff53a 100644 (file)
@@ -2,11 +2,14 @@
 #define __ASM_CRIS_SCATTERLIST_H
 
 struct scatterlist {
+#ifdef CONFIG_DEBUG_SG
+       unsigned long sg_magic;
+#endif
        char *  address;    /* Location data is to be transferred to */
        unsigned int length;
 
        /* The following is i386 highmem junk - not used by us */
-       struct page * page; /* Location for highmem page, if any */
+       unsigned long page_link;
        unsigned int offset;/* for highmem, page offset */
 
 };
index 8e827fa..99ba76e 100644 (file)
@@ -4,25 +4,28 @@
 #include <asm/types.h>
 
 /*
- * Drivers must set either ->address or (preferred) ->page and ->offset
+ * Drivers must set either ->address or (preferred) page and ->offset
  * to indicate where data must be transferred to/from.
  *
- * Using ->page is recommended since it handles highmem data as well as
+ * Using page is recommended since it handles highmem data as well as
  * low mem. ->address is restricted to data which has a virtual mapping, and
- * it will go away in the future. Updating to ->page can be automated very
+ * it will go away in the future. Updating to page can be automated very
  * easily -- something like
  *
  * sg->address = some_ptr;
  *
  * can be rewritten as
  *
- * sg->page = virt_to_page(some_ptr);
+ * sg_set_page(virt_to_page(some_ptr));
  * sg->offset = (unsigned long) some_ptr & ~PAGE_MASK;
  *
  * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
  */
 struct scatterlist {
-       struct page     *page;          /* Location for highmem page, if any */
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
        unsigned int    offset;         /* for highmem, page offset */
 
        dma_addr_t      dma_address;
index 985fdf5..d3ecdd8 100644 (file)
@@ -4,7 +4,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-       struct page     *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
        unsigned int    offset;
        dma_addr_t      dma_address;
        unsigned int    length;
index 7d5234d..d6f5787 100644 (file)
@@ -9,7 +9,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-       struct page *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long sg_magic;
+#endif
+       unsigned long page_link;
        unsigned int offset;
        unsigned int length;    /* buffer length */
 
index 352415f..1ed372c 100644 (file)
@@ -4,9 +4,12 @@
 #include <asm/types.h>
 
 struct scatterlist {
+#ifdef CONFIG_DEBUG_SG
+    unsigned long sg_magic;
+#endif
     char *  address;    /* Location data is to be transferred to, NULL for
                          * highmem page */
-    struct page * page; /* Location for highmem page, if any */
+    unsigned long page_link;
     unsigned int offset;/* for highmem, page offset */
 
     dma_addr_t dma_address;
index 24887a2..d3a7a0e 100644 (file)
@@ -4,7 +4,10 @@
 #include <linux/types.h>
 
 struct scatterlist {
-       struct page *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long sg_magic;
+#endif
+       unsigned long page_link;
        unsigned int offset;
        unsigned int length;
 
index 57e95cc..2e45ab5 100644 (file)
@@ -1 +1,11 @@
-#include <asm-m68k/module.h>
+#ifndef ASM_M68KNOMMU_MODULE_H
+#define ASM_M68KNOMMU_MODULE_H
+
+struct mod_arch_specific {
+};
+
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+
+#endif /* ASM_M68KNOMMU_MODULE_H */
index 4da79d3..afc4788 100644 (file)
@@ -5,13 +5,15 @@
 #include <asm/types.h>
 
 struct scatterlist {
-       struct page     *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
        unsigned int    offset;
        dma_addr_t      dma_address;
        unsigned int    length;
 };
 
-#define sg_address(sg)         (page_address((sg)->page) + (sg)->offset)
 #define sg_dma_address(sg)      ((sg)->dma_address)
 #define sg_dma_len(sg)          ((sg)->length)
 
index 9ed9169..68bbe9b 100644 (file)
@@ -170,10 +170,12 @@ static inline long strnlen_user(const char *src, long n)
  */
 
 static inline unsigned long
-clear_user(void *to, unsigned long n)
+__clear_user(void *to, unsigned long n)
 {
        memset(to, 0, n);
        return 0;
 }
 
+#define        clear_user(to,n)        __clear_user(to,n)
+
 #endif /* _M68KNOMMU_UACCESS_H */
index 4bf8e28..e64b410 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef _ASM_GT64120_H
 #define _ASM_GT64120_H
 
+#include <linux/clocksource.h>
+
 #include <asm/addrspace.h>
 #include <asm/byteorder.h>
 
 #define GT_READ(ofs)           le32_to_cpu(__GT_READ(ofs))
 #define GT_WRITE(ofs, data)    __GT_WRITE(ofs, cpu_to_le32(data))
 
+extern void gt641xx_set_base_clock(unsigned int clock);
+extern int gt641xx_timer0_state(void);
+
 #endif /* _ASM_GT64120_H */
index 8f689d7..affb32c 100644 (file)
@@ -2,8 +2,8 @@
  *  Machine specific IO port address definition for generic.
  *  Written by Osamu Tomita <tomita@cinet.co.jp>
  */
-#ifndef _MACH_IO_PORTS_H
-#define _MACH_IO_PORTS_H
+#ifndef __ASM_I8253_H
+#define __ASM_I8253_H
 
 /* i8253A PIT registers */
 #define PIT_MODE               0x43
@@ -27,4 +27,4 @@
 
 extern void setup_pit_timer(void);
 
-#endif /* !_MACH_IO_PORTS_H */
+#endif /* __ASM_I8253_H */
index 7af104c..83d69fe 100644 (file)
@@ -4,7 +4,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-       struct page *   page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
        unsigned int    offset;
        dma_addr_t      dma_address;
        unsigned int    length;
index 494aa65..0dad844 100644 (file)
@@ -45,13 +45,11 @@ extern unsigned int soc_type;
 extern unsigned int periph_rev;
 extern unsigned int zbbus_mhz;
 
-extern void sb1250_hpt_setup(void);
 extern void sb1250_time_init(void);
 extern void sb1250_mask_irq(int cpu, int irq);
 extern void sb1250_unmask_irq(int cpu, int irq);
 extern void sb1250_smp_finish(void);
 
-extern void bcm1480_hpt_setup(void);
 extern void bcm1480_time_init(void);
 extern void bcm1480_mask_irq(int cpu, int irq);
 extern void bcm1480_unmask_irq(int cpu, int irq);
index c68e168..f88b252 100644 (file)
@@ -1 +1,3 @@
 include include/asm-generic/Kbuild.asm
+
+unifdef-y += pdc.h
index 95f00e1..55ddb18 100644 (file)
@@ -138,7 +138,7 @@ extern void __iomem * __ioremap(unsigned long offset, unsigned long size, unsign
 /* Most machines react poorly to I/O-space being cacheable... Instead let's
  * define ioremap() in terms of ioremap_nocache().
  */
-extern inline void __iomem * ioremap(unsigned long offset, unsigned long size)
+static inline void __iomem * ioremap(unsigned long offset, unsigned long size)
 {
        return __ioremap(offset, size, _PAGE_NO_CACHE);
 }
index f6bba4c..b59a150 100644 (file)
@@ -3,6 +3,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/const.h>
+
 #if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
 # define PAGE_SHIFT    12
 #elif defined(CONFIG_PARISC_PAGE_SIZE_16KB)
@@ -12,7 +14,7 @@
 #else
 # error "unknown default kernel page size"
 #endif
-#define PAGE_SIZE      (1UL << PAGE_SHIFT)
+#define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
 
index 61fbd57..4ba868f 100644 (file)
@@ -207,7 +207,7 @@ extern struct pci_bios_ops *pci_bios;
 extern void pcibios_register_hba(struct pci_hba_data *);
 extern void pcibios_set_master(struct pci_dev *);
 #else
-extern inline void pcibios_register_hba(struct pci_hba_data *x)
+static inline void pcibios_register_hba(struct pci_hba_data *x)
 {
 }
 #endif
index 876fd81..5e0c3ca 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _PARISC_PDC_H
 #define _PARISC_PDC_H
 
-
 /*
  *     PDC return values ...
  *     All PDC calls return a subset of these errors. 
@@ -20,7 +19,6 @@
 #define PDC_BUS_POW_WARN       -12     /* Call could not complete in allowed power budget */
 #define PDC_NOT_NARROW         -17     /* Narrow mode not supported    */
 
-
 /*
  *     PDC entry points...
  */
 #define PDC_MODEL_DISPEC       5       /* disable specific option      */
 #define PDC_MODEL_CPU_ID       6       /* returns cpu-id (only newer machines!) */
 #define PDC_MODEL_CAPABILITIES 7       /* returns OS32/OS64-flags      */
+/* Values for PDC_MODEL_CAPABILITIES non-equivalent virtual aliasing support */
+#define  PDC_MODEL_IOPDIR_FDC          (1 << 2)
+#define  PDC_MODEL_NVA_MASK            (3 << 4)
+#define  PDC_MODEL_NVA_SUPPORTED       (0 << 4)
+#define  PDC_MODEL_NVA_SLOW            (1 << 4)
+#define  PDC_MODEL_NVA_UNSUPPORTED     (3 << 4)
 #define PDC_MODEL_GET_BOOT__OP 8       /* returns boot test options    */
 #define PDC_MODEL_SET_BOOT__OP 9       /* set boot test options        */
 
@@ -91,7 +95,7 @@
 #define PDC_TOD                9               /* time-of-day clock (TOD)      */
 #define PDC_TOD_READ           0       /* read TOD                     */
 #define PDC_TOD_WRITE          1       /* write TOD                    */
-#define PDC_TOD_ITIMER         2       /* calibrate Interval Timer (CR16) */
+
 
 #define PDC_STABLE     10              /* stable storage (sprockets)   */
 #define PDC_STABLE_READ                0
 #define PDC_MEM_RET_PDT_FULL           -11
 #define PDC_MEM_RET_INVALID_PHYSICAL_LOCATION ~0ULL
 
-#ifndef __ASSEMBLY__
-typedef struct {
-    unsigned long long baseAddr;
-    unsigned int       pages;
-    unsigned int       reserved;
-} MemAddrTable_t;
-#endif
-
-
 #define PDC_PSW                21              /* Get/Set default System Mask  */
 #define PDC_PSW_MASK           0       /* Return mask                  */
 #define PDC_PSW_GET_DEFAULTS   1       /* Return defaults              */
@@ -274,6 +269,43 @@ typedef struct {
 #define PDC_LINK_PCI_ENTRY_POINTS      0  /* list (Arg1) = 0 */
 #define PDC_LINK_USB_ENTRY_POINTS      1  /* list (Arg1) = 1 */
 
+/* cl_class
+ * page 3-33 of IO-Firmware ARS
+ * IODC ENTRY_INIT(Search first) RET[1]
+ */
+#define        CL_NULL         0       /* invalid */
+#define        CL_RANDOM       1       /* random access (as disk) */
+#define        CL_SEQU         2       /* sequential access (as tape) */
+#define        CL_DUPLEX       7       /* full-duplex point-to-point (RS-232, Net) */
+#define        CL_KEYBD        8       /* half-duplex console (HIL Keyboard) */
+#define        CL_DISPL        9       /* half-duplex console (display) */
+#define        CL_FC           10      /* FiberChannel access media */
+
+/* IODC ENTRY_INIT() */
+#define ENTRY_INIT_SRCH_FRST   2
+#define ENTRY_INIT_SRCH_NEXT   3
+#define ENTRY_INIT_MOD_DEV     4
+#define ENTRY_INIT_DEV         5
+#define ENTRY_INIT_MOD         6
+#define ENTRY_INIT_MSG         9
+
+/* IODC ENTRY_IO() */
+#define ENTRY_IO_BOOTIN                0
+#define ENTRY_IO_BOOTOUT       1
+#define ENTRY_IO_CIN           2
+#define ENTRY_IO_COUT          3
+#define ENTRY_IO_CLOSE         4
+#define ENTRY_IO_GETMSG                9
+#define ENTRY_IO_BBLOCK_IN     16
+#define ENTRY_IO_BBLOCK_OUT    17
+
+/* IODC ENTRY_SPA() */
+
+/* IODC ENTRY_CONFIG() */
+
+/* IODC ENTRY_TEST() */
+
+/* IODC ENTRY_TLB() */
 
 /* constants for OS (NVM...) */
 #define OS_ID_NONE             0       /* Undefined OS ID      */
@@ -295,7 +327,13 @@ typedef struct {
 #define OSTAT_RUN              6
 #define OSTAT_ON               7
 
-#ifndef __ASSEMBLY__
+/* Page Zero constant offsets used by the HPMC handler */
+#define BOOT_CONSOLE_HPA_OFFSET  0x3c0
+#define BOOT_CONSOLE_SPA_OFFSET  0x3c4
+#define BOOT_CONSOLE_PATH_OFFSET 0x3a8
+
+#if !defined(__ASSEMBLY__)
+#ifdef __KERNEL__
 
 #include <linux/types.h>
 
@@ -331,14 +369,6 @@ struct pdc_model {         /* for PDC_MODEL */
        unsigned long curr_key;
 };
 
-/* Values for PDC_MODEL_CAPABILITIES non-equivalent virtual aliasing support */
-
-#define PDC_MODEL_IOPDIR_FDC            (1 << 2)        /* see sba_iommu.c */
-#define PDC_MODEL_NVA_MASK             (3 << 4)
-#define PDC_MODEL_NVA_SUPPORTED                (0 << 4)
-#define PDC_MODEL_NVA_SLOW             (1 << 4)
-#define PDC_MODEL_NVA_UNSUPPORTED      (3 << 4)
-
 struct pdc_cache_cf {          /* for PDC_CACHE  (I/D-caches) */
     unsigned long
 #ifdef CONFIG_64BIT
@@ -558,15 +588,97 @@ struct pdc_hpmc_pim_20 { /* PDC_PIM */
        __u64 fr[32];
 };
 
-#endif /* __ASSEMBLY__ */
+void pdc_console_init(void);   /* in pdc_console.c */
+void pdc_console_restart(void);
+
+void setup_pdc(void);          /* in inventory.c */
+
+/* wrapper-functions from pdc.c */
+
+int pdc_add_valid(unsigned long address);
+int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
+int pdc_chassis_disp(unsigned long disp);
+int pdc_chassis_warn(unsigned long *warn);
+int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
+int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
+                 void *iodc_data, unsigned int iodc_data_size);
+int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
+                            struct pdc_module_path *mod_path, long mod_index);
+int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info,
+                             long mod_index, long addr_index);
+int pdc_model_info(struct pdc_model *model);
+int pdc_model_sysmodel(char *name);
+int pdc_model_cpuid(unsigned long *cpu_id);
+int pdc_model_versions(unsigned long *versions, int id);
+int pdc_model_capabilities(unsigned long *capabilities);
+int pdc_cache_info(struct pdc_cache_info *cache);
+int pdc_spaceid_bits(unsigned long *space_bits);
+#ifndef CONFIG_PA20
+int pdc_btlb_info(struct pdc_btlb_info *btlb);
+int pdc_mem_map_hpa(struct pdc_memory_map *r_addr, struct pdc_module_path *mod_path);
+#endif /* !CONFIG_PA20 */
+int pdc_lan_station_id(char *lan_addr, unsigned long net_hpa);
+
+int pdc_stable_read(unsigned long staddr, void *memaddr, unsigned long count);
+int pdc_stable_write(unsigned long staddr, void *memaddr, unsigned long count);
+int pdc_stable_get_size(unsigned long *size);
+int pdc_stable_verify_contents(void);
+int pdc_stable_initialize(void);
+
+int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa);
+int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl);
+
+int pdc_get_initiator(struct hardware_path *, struct pdc_initiator *);
+int pdc_tod_read(struct pdc_tod *tod);
+int pdc_tod_set(unsigned long sec, unsigned long usec);
+
+#ifdef CONFIG_64BIT
+int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
+               struct pdc_memory_table *tbl, unsigned long entries);
+#endif
+
+void set_firmware_width(void);
+int pdc_do_firm_test_reset(unsigned long ftc_bitmap);
+int pdc_do_reset(void);
+int pdc_soft_power_info(unsigned long *power_reg);
+int pdc_soft_power_button(int sw_control);
+void pdc_io_reset(void);
+void pdc_io_reset_devices(void);
+int pdc_iodc_getc(void);
+void pdc_iodc_putc(unsigned char c);
+void pdc_iodc_outc(unsigned char c);
+void pdc_printf(const char *fmt, ...);
+
+void pdc_emergency_unlock(void);
+int pdc_sti_call(unsigned long func, unsigned long flags,
+                 unsigned long inptr, unsigned long outputr,
+                 unsigned long glob_cfg);
+
+static inline char * os_id_to_string(u16 os_id) {
+       switch(os_id) {
+       case OS_ID_NONE:        return "No OS";
+       case OS_ID_HPUX:        return "HP-UX";
+       case OS_ID_MPEXL:       return "MPE-iX";
+       case OS_ID_OSF:         return "OSF";
+       case OS_ID_HPRT:        return "HP-RT";
+       case OS_ID_NOVEL:       return "Novell Netware";
+       case OS_ID_LINUX:       return "Linux";
+       default:        return "Unknown";
+       }
+}
+
+#endif /* __KERNEL__ */
+
+#define PAGE0   ((struct zeropage *)__PAGE_OFFSET)
+
+/* DEFINITION OF THE ZERO-PAGE (PAG0) */
+/* based on work by Jason Eckhardt (jason@equator.com) */
 
-/* flags of the device_path (see below) */
+/* flags of the device_path */
 #define        PF_AUTOBOOT     0x80
 #define        PF_AUTOSEARCH   0x40
 #define        PF_TIMER        0x0F
 
-#ifndef __ASSEMBLY__
-
 struct device_path {           /* page 1-69 */
        unsigned char flags;    /* flags see above! */
        unsigned char bc[6];    /* bus converter routing info */
@@ -586,63 +698,6 @@ struct pz_device {
        unsigned short cl_class;/* see below */
 } __attribute__((aligned(8))) ;
 
-#endif /* __ASSEMBLY__ */
-
-/* cl_class
- * page 3-33 of IO-Firmware ARS
- * IODC ENTRY_INIT(Search first) RET[1]
- */
-#define        CL_NULL         0       /* invalid */
-#define        CL_RANDOM       1       /* random access (as disk) */
-#define        CL_SEQU         2       /* sequential access (as tape) */
-#define        CL_DUPLEX       7       /* full-duplex point-to-point (RS-232, Net) */
-#define        CL_KEYBD        8       /* half-duplex console (HIL Keyboard) */
-#define        CL_DISPL        9       /* half-duplex console (display) */
-#define        CL_FC           10      /* FiberChannel access media */
-
-#if 0
-/* FIXME: DEVCLASS_* duplicates CL_* (above).  Delete DEVCLASS_*? */
-#define DEVCLASS_RANDOM                1
-#define DEVCLASS_SEQU          2
-#define DEVCLASS_DUPLEX                7
-#define DEVCLASS_KEYBD         8
-#define DEVCLASS_DISP          9
-#endif
-
-/* IODC ENTRY_INIT() */
-#define ENTRY_INIT_SRCH_FRST   2
-#define ENTRY_INIT_SRCH_NEXT   3
-#define ENTRY_INIT_MOD_DEV     4
-#define ENTRY_INIT_DEV         5
-#define ENTRY_INIT_MOD         6
-#define ENTRY_INIT_MSG         9
-
-/* IODC ENTRY_IO() */
-#define ENTRY_IO_BOOTIN                0
-#define ENTRY_IO_BOOTOUT       1
-#define ENTRY_IO_CIN           2
-#define ENTRY_IO_COUT          3
-#define ENTRY_IO_CLOSE         4
-#define ENTRY_IO_GETMSG                9
-#define ENTRY_IO_BBLOCK_IN     16
-#define ENTRY_IO_BBLOCK_OUT    17
-
-/* IODC ENTRY_SPA() */
-
-/* IODC ENTRY_CONFIG() */
-
-/* IODC ENTRY_TEST() */
-
-/* IODC ENTRY_TLB() */
-
-
-/* DEFINITION OF THE ZERO-PAGE (PAG0) */
-/* based on work by Jason Eckhardt (jason@equator.com) */
-
-#ifndef __ASSEMBLY__
-
-#define PAGE0   ((struct zeropage *)__PAGE_OFFSET)
-
 struct zeropage {
        /* [0x000] initialize vectors (VEC) */
        unsigned int    vec_special;            /* must be zero */
@@ -699,93 +754,6 @@ struct zeropage {
        __u32   pad608[126];
 };
 
-#endif /* __ASSEMBLY__ */
-
-/* Page Zero constant offsets used by the HPMC handler */
-
-#define BOOT_CONSOLE_HPA_OFFSET  0x3c0
-#define BOOT_CONSOLE_SPA_OFFSET  0x3c4
-#define BOOT_CONSOLE_PATH_OFFSET 0x3a8
-
-#ifndef __ASSEMBLY__
-void pdc_console_init(void);   /* in pdc_console.c */
-void pdc_console_restart(void);
-
-void setup_pdc(void);          /* in inventory.c */
-
-/* wrapper-functions from pdc.c */
-
-int pdc_add_valid(unsigned long address);
-int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
-int pdc_chassis_disp(unsigned long disp);
-int pdc_chassis_warn(unsigned long *warn);
-int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
-int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
-                 void *iodc_data, unsigned int iodc_data_size);
-int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
-                            struct pdc_module_path *mod_path, long mod_index);
-int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info, 
-                             long mod_index, long addr_index);
-int pdc_model_info(struct pdc_model *model);
-int pdc_model_sysmodel(char *name);
-int pdc_model_cpuid(unsigned long *cpu_id);
-int pdc_model_versions(unsigned long *versions, int id);
-int pdc_model_capabilities(unsigned long *capabilities);
-int pdc_cache_info(struct pdc_cache_info *cache);
-int pdc_spaceid_bits(unsigned long *space_bits);
-#ifndef CONFIG_PA20
-int pdc_btlb_info(struct pdc_btlb_info *btlb);
-int pdc_mem_map_hpa(struct pdc_memory_map *r_addr, struct pdc_module_path *mod_path);
-#endif /* !CONFIG_PA20 */
-int pdc_lan_station_id(char *lan_addr, unsigned long net_hpa);
-
-int pdc_stable_read(unsigned long staddr, void *memaddr, unsigned long count);
-int pdc_stable_write(unsigned long staddr, void *memaddr, unsigned long count);
-int pdc_stable_get_size(unsigned long *size);
-int pdc_stable_verify_contents(void);
-int pdc_stable_initialize(void);
-
-int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa);
-int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl);
-
-int pdc_get_initiator(struct hardware_path *, struct pdc_initiator *);
-int pdc_tod_read(struct pdc_tod *tod);
-int pdc_tod_set(unsigned long sec, unsigned long usec);
-
-#ifdef CONFIG_64BIT
-int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
-               struct pdc_memory_table *tbl, unsigned long entries);
-#endif
-
-void set_firmware_width(void);
-int pdc_do_firm_test_reset(unsigned long ftc_bitmap);
-int pdc_do_reset(void);
-int pdc_soft_power_info(unsigned long *power_reg);
-int pdc_soft_power_button(int sw_control);
-void pdc_io_reset(void);
-void pdc_io_reset_devices(void);
-int pdc_iodc_getc(void);
-void pdc_iodc_putc(unsigned char c);
-void pdc_iodc_outc(unsigned char c);
-void pdc_printf(const char *fmt, ...);
-
-void pdc_emergency_unlock(void);
-int pdc_sti_call(unsigned long func, unsigned long flags,
-                 unsigned long inptr, unsigned long outputr,
-                 unsigned long glob_cfg);
-
-static inline char * os_id_to_string(u16 os_id) {
-       switch(os_id) {
-       case OS_ID_NONE:        return "No OS";
-       case OS_ID_HPUX:        return "HP-UX";
-       case OS_ID_MPEXL:       return "MPE-iX";
-       case OS_ID_OSF:         return "OSF";
-       case OS_ID_HPRT:        return "HP-RT";
-       case OS_ID_NOVEL:       return "Novell Netware";
-       case OS_ID_LINUX:       return "Linux";
-       default:        return "Unknown";
-       }
-}
-#endif /* __ASSEMBLY__ */
+#endif /* !defined(__ASSEMBLY__) */
 
 #endif /* _PARISC_PDC_H */
index 9ab79c8..cd0fa4f 100644 (file)
 #define pgd_ERROR(e) \
        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
 
- /* Note: If you change ISTACK_SIZE, you need to change the corresponding
-  * values in vmlinux.lds and vmlinux64.lds (init_istack section). Also,
-  * the "order" and size need to agree.
-  */
-
-#define  ISTACK_SIZE  32768 /* Interrupt Stack Size */
-#define  ISTACK_ORDER 3
-
 /* This is the size of the initially mapped kernel memory */
 #ifdef CONFIG_64BIT
 #define KERNEL_INITIAL_ORDER   24      /* 0 to 1<<24 = 16MB */
@@ -325,27 +317,27 @@ static inline void pgd_clear(pgd_t *pgd) {
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
  * into the pgd entry)
  */
-extern inline int pgd_none(pgd_t pgd)          { return 0; }
-extern inline int pgd_bad(pgd_t pgd)           { return 0; }
-extern inline int pgd_present(pgd_t pgd)       { return 1; }
-extern inline void pgd_clear(pgd_t * pgdp)     { }
+static inline int pgd_none(pgd_t pgd)          { return 0; }
+static inline int pgd_bad(pgd_t pgd)           { return 0; }
+static inline int pgd_present(pgd_t pgd)       { return 1; }
+static inline void pgd_clear(pgd_t * pgdp)     { }
 #endif
 
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
-extern inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
-extern inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_WRITE; }
-extern inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
-
-extern inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte)       { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_WRITE; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) |= _PAGE_WRITE; return pte; }
+static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_WRITE; }
+static inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
+
+static inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkold(pte_t pte)       { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_WRITE; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) |= _PAGE_WRITE; return pte; }
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -369,7 +361,7 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
        return pte;
 }
 
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
 /* Permanent address of a page.  On parisc we don't have highmem. */
index 5d02172..c5edc60 100644 (file)
@@ -19,7 +19,7 @@
 #ifdef CONFIG_PREFETCH
 
 #define ARCH_HAS_PREFETCH
-extern inline void prefetch(const void *addr)
+static inline void prefetch(const void *addr)
 {
        __asm__("ldw 0(%0), %%r0" : : "r" (addr));
 }
@@ -27,7 +27,7 @@ extern inline void prefetch(const void *addr)
 /* LDD is a PA2.0 addition. */
 #ifdef CONFIG_PA20
 #define ARCH_HAS_PREFETCHW
-extern inline void prefetchw(const void *addr)
+static inline void prefetchw(const void *addr)
 {
        __asm__("ldd 0(%0), %%r0" : : "r" (addr));
 }
index f4ebff1..099d641 100644 (file)
@@ -50,10 +50,10 @@ static inline unsigned int get_rtc_time(struct rtc_time *wtime)
        long int days, rem, y;
        const unsigned short int *ip;
 
-       if(pdc_tod_read(&tod_data) < 0)
+       memset(wtime, 0, sizeof(*wtime));
+       if (pdc_tod_read(&tod_data) < 0)
                return RTC_24H | RTC_BATT_BAD;
 
-
        // most of the remainder of this function is:
 //     Copyright (C) 1991, 1993, 1997, 1998 Free Software Foundation, Inc.
 //     This was originally a part of the GNU C Library.
index e7211c7..62269b3 100644 (file)
@@ -5,7 +5,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-       struct page *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long sg_magic;
+#endif
+       unsigned long page_link;
        unsigned int offset;
 
        unsigned int length;
@@ -15,7 +18,7 @@ struct scatterlist {
        __u32      iova_length; /* bytes mapped */
 };
 
-#define sg_virt_addr(sg) ((unsigned long)(page_address(sg->page) + sg->offset))
+#define sg_virt_addr(sg) ((unsigned long)sg_virt(sg))
 #define sg_dma_address(sg) ((sg)->iova)
 #define sg_dma_len(sg)     ((sg)->iova_length)
 
index b771dcf..a16271c 100644 (file)
@@ -54,7 +54,7 @@ struct semaphore {
 
 #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
 
-extern inline void sema_init (struct semaphore *sem, int val)
+static inline void sema_init (struct semaphore *sem, int val)
 {
        *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
 }
@@ -82,7 +82,7 @@ asmlinkage void __up(struct semaphore * sem);
  * interrupts while we're messing with the semaphore.  Sorry.
  */
 
-extern __inline__ void down(struct semaphore * sem)
+static inline void down(struct semaphore * sem)
 {
        might_sleep();
        spin_lock_irq(&sem->sentry);
@@ -94,7 +94,7 @@ extern __inline__ void down(struct semaphore * sem)
        spin_unlock_irq(&sem->sentry);
 }
 
-extern __inline__ int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
 {
        int ret = 0;
        might_sleep();
@@ -112,7 +112,7 @@ extern __inline__ int down_interruptible(struct semaphore * sem)
  * down_trylock returns 0 on success, 1 if we failed to get the lock.
  * May not sleep, but must preserve irq state
  */
-extern __inline__ int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
 {
        unsigned long flags;
        int count;
@@ -129,7 +129,7 @@ extern __inline__ int down_trylock(struct semaphore * sem)
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
  */
-extern __inline__ void up(struct semaphore * sem)
+static inline void up(struct semaphore * sem)
 {
        unsigned long flags;
 
index f74099b..081b4ae 100644 (file)
 #define __NR_signalfd          (__NR_Linux + 302)
 #define __NR_timerfd           (__NR_Linux + 303)
 #define __NR_eventfd           (__NR_Linux + 304)
+#define __NR_fallocate         (__NR_Linux + 305)
 
-#define __NR_Linux_syscalls    (__NR_eventfd + 1)
+#define __NR_Linux_syscalls    (__NR_fallocate + 1)
 
 
 #define __IGNORE_select                /* newselect */
index 65be95d..ff52013 100644 (file)
@@ -285,9 +285,9 @@ dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
        BUG_ON(direction == DMA_NONE);
 
        for_each_sg(sgl, sg, nents, i) {
-               BUG_ON(!sg->page);
-               __dma_sync_page(sg->page, sg->offset, sg->length, direction);
-               sg->dma_address = page_to_bus(sg->page) + sg->offset;
+               BUG_ON(!sg_page(sg));
+               __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
+               sg->dma_address = page_to_bus(sg_page(sg)) + sg->offset;
        }
 
        return nents;
@@ -328,7 +328,7 @@ static inline void dma_sync_sg_for_cpu(struct device *dev,
        BUG_ON(direction == DMA_NONE);
 
        for_each_sg(sgl, sg, nents, i)
-               __dma_sync_page(sg->page, sg->offset, sg->length, direction);
+               __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
 }
 
 static inline void dma_sync_sg_for_device(struct device *dev,
@@ -341,7 +341,7 @@ static inline void dma_sync_sg_for_device(struct device *dev,
        BUG_ON(direction == DMA_NONE);
 
        for_each_sg(sgl, sg, nents, i)
-               __dma_sync_page(sg->page, sg->offset, sg->length, direction);
+               __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
 }
 
 static inline int dma_mapping_error(dma_addr_t dma_addr)
index 568135f..fcb2ebb 100644 (file)
 
 #include <linux/suspend.h>
 
+/* Variants of the 5200(B) */
+#define MPC5200_SVR            0x80110010
+#define MPC5200_SVR_MASK       0xfffffff0
+#define MPC5200B_SVR           0x80110020
+#define MPC5200B_SVR_MASK      0xfffffff0
 
 /* ======================================================================== */
 /* Structures mapping of some unit register set                             */
@@ -244,6 +249,7 @@ struct mpc52xx_cdm {
 #ifndef __ASSEMBLY__
 
 extern void __iomem * mpc52xx_find_and_map(const char *);
+extern void __iomem * mpc52xx_find_and_map_path(const char *path);
 extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node);
 extern void mpc5200_setup_xlb_arbiter(void);
 extern void mpc52xx_declare_of_platform_devices(void);
@@ -253,6 +259,9 @@ extern unsigned int mpc52xx_get_irq(void);
 
 extern int __init mpc52xx_add_bridge(struct device_node *node);
 
+extern void __init mpc52xx_map_wdt(void);
+extern void mpc52xx_restart(char *cmd);
+
 #endif /* __ASSEMBLY__ */
 
 #ifdef CONFIG_PM
index b075f61..fcf7d55 100644 (file)
 #include <asm/dma.h>
 
 struct scatterlist {
-       struct page *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long sg_magic;
+#endif
+       unsigned long page_link;
        unsigned int offset;
        unsigned int length;
 
index cc45780..51df94c 100644 (file)
@@ -33,6 +33,7 @@
 
 #define set_mb(var, value)     do { var = value; mb(); } while (0)
 
+#define AT_VECTOR_SIZE_ARCH 6 /* entries in ARCH_DLINFO */
 #ifdef CONFIG_SMP
 #define smp_mb()       mb()
 #define smp_rmb()      rmb()
diff --git a/include/asm-s390/cpu.h b/include/asm-s390/cpu.h
new file mode 100644 (file)
index 0000000..352dde1
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *  include/asm-s390/cpu.h
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_CPU_H_
+#define _ASM_S390_CPU_H_
+
+#include <linux/types.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
+
+struct s390_idle_data {
+       spinlock_t lock;
+       unsigned int in_idle;
+       unsigned long long idle_count;
+       unsigned long long idle_enter;
+       unsigned long long idle_time;
+};
+
+DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
+
+#endif /* _ASM_S390_CPU_H_ */
index 501cb9b..05b8421 100644 (file)
 
 #ifndef __s390x__
 #define LCTL_OPCODE "lctl"
-#define PGTABLE_BITS (_SEGMENT_TABLE|USER_STD_MASK)
 #else
 #define LCTL_OPCODE "lctlg"
-#define PGTABLE_BITS (_REGION_TABLE|USER_STD_MASK)
 #endif
 
-static inline void enter_lazy_tlb(struct mm_struct *mm,
-                                  struct task_struct *tsk)
+static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
 {
+       pgd_t *pgd = mm->pgd;
+       unsigned long asce_bits;
+
+       /* Calculate asce bits from the first pgd table entry. */
+       asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
+#ifdef CONFIG_64BIT
+       asce_bits |= _ASCE_TYPE_REGION3;
+#endif
+       S390_lowcore.user_asce = asce_bits | __pa(pgd);
+       if (switch_amode) {
+               /* Load primary space page table origin. */
+               pgd_t *shadow_pgd = get_shadow_table(pgd) ? : pgd;
+               S390_lowcore.user_exec_asce = asce_bits | __pa(shadow_pgd);
+               asm volatile(LCTL_OPCODE" 1,1,%0\n"
+                            : : "m" (S390_lowcore.user_exec_asce) );
+       } else
+               /* Load home space page table origin. */
+               asm volatile(LCTL_OPCODE" 13,13,%0"
+                            : : "m" (S390_lowcore.user_asce) );
 }
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                             struct task_struct *tsk)
 {
-       pgd_t *shadow_pgd = get_shadow_pgd(next->pgd);
-
-       if (prev != next) {
-               S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) |
-                                        PGTABLE_BITS;
-               if (shadow_pgd) {
-                       /* Load primary/secondary space page table origin. */
-                       S390_lowcore.user_exec_asce =
-                               (__pa(shadow_pgd) & PAGE_MASK) | PGTABLE_BITS;
-                       asm volatile(LCTL_OPCODE" 1,1,%0\n"
-                                    LCTL_OPCODE" 7,7,%1"
-                                    : : "m" (S390_lowcore.user_exec_asce),
-                                        "m" (S390_lowcore.user_asce) );
-               } else if (switch_amode) {
-                       /* Load primary space page table origin. */
-                       asm volatile(LCTL_OPCODE" 1,1,%0"
-                                    : : "m" (S390_lowcore.user_asce) );
-               } else
-                       /* Load home space page table origin. */
-                       asm volatile(LCTL_OPCODE" 13,13,%0"
-                                    : : "m" (S390_lowcore.user_asce) );
-       }
+       if (unlikely(prev == next))
+               return;
        cpu_set(smp_processor_id(), next->cpu_vm_mask);
+       update_mm(next, tsk);
 }
 
+#define enter_lazy_tlb(mm,tsk) do { } while (0)
 #define deactivate_mm(tsk,mm)  do { } while (0)
 
 static inline void activate_mm(struct mm_struct *prev,
index ceec382..584d0ee 100644 (file)
@@ -82,6 +82,7 @@ typedef struct { unsigned long pte; } pte_t;
 #ifndef __s390x__
 
 typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pud; } pud_t;
 typedef struct {
         unsigned long pgd0;
         unsigned long pgd1;
@@ -90,6 +91,7 @@ typedef struct {
         } pgd_t;
 
 #define pmd_val(x)      ((x).pmd)
+#define pud_val(x)     ((x).pud)
 #define pgd_val(x)      ((x).pgd0)
 
 #else /* __s390x__ */
@@ -98,10 +100,12 @@ typedef struct {
         unsigned long pmd0;
         unsigned long pmd1; 
         } pmd_t;
+typedef struct { unsigned long pud; } pud_t;
 typedef struct { unsigned long pgd; } pgd_t;
 
 #define pmd_val(x)      ((x).pmd0)
 #define pmd_val1(x)     ((x).pmd1)
+#define pud_val(x)     ((x).pud)
 #define pgd_val(x)      ((x).pgd)
 
 #endif /* __s390x__ */
index e45d3c9..709dd17 100644 (file)
 
 #define check_pgt_cache()      do {} while (0)
 
-/*
- * Page allocation orders.
- */
-#ifndef __s390x__
-# define PTE_ALLOC_ORDER       0
-# define PMD_ALLOC_ORDER       0
-# define PGD_ALLOC_ORDER       1
-#else /* __s390x__ */
-# define PTE_ALLOC_ORDER       0
-# define PMD_ALLOC_ORDER       2
-# define PGD_ALLOC_ORDER       2
-#endif /* __s390x__ */
+unsigned long *crst_table_alloc(struct mm_struct *, int);
+void crst_table_free(unsigned long *);
 
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
+unsigned long *page_table_alloc(int);
+void page_table_free(unsigned long *);
 
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
 {
-       pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER);
-       int i;
-
-       if (!pgd)
-               return NULL;
-       if (s390_noexec) {
-               pgd_t *shadow_pgd = (pgd_t *)
-                       __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER);
-               struct page *page = virt_to_page(pgd);
-
-               if (!shadow_pgd) {
-                       free_pages((unsigned long) pgd, PGD_ALLOC_ORDER);
-                       return NULL;
-               }
-               page->lru.next = (void *) shadow_pgd;
-       }
-       for (i = 0; i < PTRS_PER_PGD; i++)
-#ifndef __s390x__
-               pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE));
+       *s = val;
+       n = (n / 256) - 1;
+       asm volatile(
+#ifdef CONFIG_64BIT
+               "       mvc     8(248,%0),0(%0)\n"
 #else
-               pgd_clear(pgd + i);
+               "       mvc     4(252,%0),0(%0)\n"
 #endif
-       return pgd;
+               "0:     mvc     256(256,%0),0(%0)\n"
+               "       la      %0,256(%0)\n"
+               "       brct    %1,0b\n"
+               : "+a" (s), "+d" (n));
 }
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void crst_table_init(unsigned long *crst, unsigned long entry)
 {
-       pgd_t *shadow_pgd = get_shadow_pgd(pgd);
-
-       if (shadow_pgd)
-               free_pages((unsigned long) shadow_pgd, PGD_ALLOC_ORDER);
-       free_pages((unsigned long) pgd, PGD_ALLOC_ORDER);
+       clear_table(crst, entry, sizeof(unsigned long)*2048);
+       crst = get_shadow_table(crst);
+       if (crst)
+               clear_table(crst, entry, sizeof(unsigned long)*2048);
 }
 
 #ifndef __s390x__
-/*
- * page middle directory allocation/free routines.
- * We use pmd cache only on s390x, so these are dummy routines. This
- * code never triggers because the pgd will always be present.
- */
-#define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(x)                     do { } while (0)
-#define __pmd_free_tlb(tlb,x)          do { } while (0)
-#define pgd_populate(mm, pmd, pte)      BUG()
-#define pgd_populate_kernel(mm, pmd, pte)      BUG()
-#else /* __s390x__ */
-static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
+
+static inline unsigned long pgd_entry_type(struct mm_struct *mm)
 {
-       pmd_t *pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER);
-       int i;
-
-       if (!pmd)
-               return NULL;
-       if (s390_noexec) {
-               pmd_t *shadow_pmd = (pmd_t *)
-                       __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER);
-               struct page *page = virt_to_page(pmd);
-
-               if (!shadow_pmd) {
-                       free_pages((unsigned long) pmd, PMD_ALLOC_ORDER);
-                       return NULL;
-               }
-               page->lru.next = (void *) shadow_pmd;
-       }
-       for (i=0; i < PTRS_PER_PMD; i++)
-               pmd_clear(pmd + i);
-       return pmd;
+       return _SEGMENT_ENTRY_EMPTY;
 }
 
-static inline void pmd_free (pmd_t *pmd)
+#define pud_alloc_one(mm,address)              ({ BUG(); ((pud_t *)2); })
+#define pud_free(x)                            do { } while (0)
+
+#define pmd_alloc_one(mm,address)              ({ BUG(); ((pmd_t *)2); })
+#define pmd_free(x)                            do { } while (0)
+
+#define pgd_populate(mm, pgd, pud)             BUG()
+#define pgd_populate_kernel(mm, pgd, pud)      BUG()
+
+#define pud_populate(mm, pud, pmd)             BUG()
+#define pud_populate_kernel(mm, pud, pmd)      BUG()
+
+#else /* __s390x__ */
+
+static inline unsigned long pgd_entry_type(struct mm_struct *mm)
 {
-       pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+       return _REGION3_ENTRY_EMPTY;
+}
+
+#define pud_alloc_one(mm,address)              ({ BUG(); ((pud_t *)2); })
+#define pud_free(x)                            do { } while (0)
 
-       if (shadow_pmd)
-               free_pages((unsigned long) shadow_pmd, PMD_ALLOC_ORDER);
-       free_pages((unsigned long) pmd, PMD_ALLOC_ORDER);
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
+{
+       unsigned long *crst = crst_table_alloc(mm, s390_noexec);
+       if (crst)
+               crst_table_init(crst, _SEGMENT_ENTRY_EMPTY);
+       return (pmd_t *) crst;
 }
+#define pmd_free(pmd) crst_table_free((unsigned long *) pmd)
 
-#define __pmd_free_tlb(tlb,pmd)                        \
-       do {                                    \
-               tlb_flush_mmu(tlb, 0, 0);       \
-               pmd_free(pmd);                  \
-        } while (0)
+#define pgd_populate(mm, pgd, pud)             BUG()
+#define pgd_populate_kernel(mm, pgd, pud)      BUG()
 
-static inline void
-pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+static inline void pud_populate_kernel(struct mm_struct *mm,
+                                      pud_t *pud, pmd_t *pmd)
 {
-       pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd);
+       pud_val(*pud) = _REGION3_ENTRY | __pa(pmd);
 }
 
-static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 {
-       pgd_t *shadow_pgd = get_shadow_pgd(pgd);
-       pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+       pud_t *shadow_pud = get_shadow_table(pud);
+       pmd_t *shadow_pmd = get_shadow_table(pmd);
 
-       if (shadow_pgd && shadow_pmd)
-               pgd_populate_kernel(mm, shadow_pgd, shadow_pmd);
-       pgd_populate_kernel(mm, pgd, pmd);
+       if (shadow_pud && shadow_pmd)
+               pud_populate_kernel(mm, shadow_pud, shadow_pmd);
+       pud_populate_kernel(mm, pud, pmd);
 }
 
 #endif /* __s390x__ */
 
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+       unsigned long *crst = crst_table_alloc(mm, s390_noexec);
+       if (crst)
+               crst_table_init(crst, pgd_entry_type(mm));
+       return (pgd_t *) crst;
+}
+#define pgd_free(pgd) crst_table_free((unsigned long *) pgd)
+
 static inline void 
 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
 #ifndef __s390x__
-       pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte);
-       pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte+256);
-       pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte+512);
-       pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte+768);
+       pmd_val(pmd[0]) = _SEGMENT_ENTRY + __pa(pte);
+       pmd_val(pmd[1]) = _SEGMENT_ENTRY + __pa(pte+256);
+       pmd_val(pmd[2]) = _SEGMENT_ENTRY + __pa(pte+512);
+       pmd_val(pmd[3]) = _SEGMENT_ENTRY + __pa(pte+768);
 #else /* __s390x__ */
-       pmd_val(*pmd) = _PMD_ENTRY + __pa(pte);
-       pmd_val1(*pmd) = _PMD_ENTRY + __pa(pte+256);
+       pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte);
+       pmd_val1(*pmd) = _SEGMENT_ENTRY + __pa(pte+256);
 #endif /* __s390x__ */
 }
 
@@ -160,7 +135,7 @@ static inline void
 pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page)
 {
        pte_t *pte = (pte_t *)page_to_phys(page);
-       pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+       pmd_t *shadow_pmd = get_shadow_table(pmd);
        pte_t *shadow_pte = get_shadow_pte(pte);
 
        pmd_populate_kernel(mm, pmd, pte);
@@ -171,67 +146,14 @@ pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page)
 /*
  * page table entry allocation/free routines.
  */
-static inline pte_t *
-pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr)
-{
-       pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL|__GFP_REPEAT);
-       int i;
-
-       if (!pte)
-               return NULL;
-       if (s390_noexec) {
-               pte_t *shadow_pte = (pte_t *)
-                       __get_free_page(GFP_KERNEL|__GFP_REPEAT);
-               struct page *page = virt_to_page(pte);
-
-               if (!shadow_pte) {
-                       free_page((unsigned long) pte);
-                       return NULL;
-               }
-               page->lru.next = (void *) shadow_pte;
-       }
-       for (i=0; i < PTRS_PER_PTE; i++) {
-               pte_clear(mm, vmaddr, pte + i);
-               vmaddr += PAGE_SIZE;
-       }
-       return pte;
-}
-
-static inline struct page *
-pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
-{
-       pte_t *pte = pte_alloc_one_kernel(mm, vmaddr);
-       if (pte)
-               return virt_to_page(pte);
-       return NULL;
-}
-
-static inline void pte_free_kernel(pte_t *pte)
-{
-       pte_t *shadow_pte = get_shadow_pte(pte);
-
-       if (shadow_pte)
-               free_page((unsigned long) shadow_pte);
-       free_page((unsigned long) pte);
-}
-
-static inline void pte_free(struct page *pte)
-{
-       struct page *shadow_page = get_shadow_page(pte);
-
-       if (shadow_page)
-               __free_page(shadow_page);
-       __free_page(pte);
-}
-
-#define __pte_free_tlb(tlb, pte)                                       \
-({                                                                     \
-       struct mmu_gather *__tlb = (tlb);                               \
-       struct page *__pte = (pte);                                     \
-       struct page *shadow_page = get_shadow_page(__pte);              \
-       if (shadow_page)                                                \
-               tlb_remove_page(__tlb, shadow_page);                    \
-       tlb_remove_page(__tlb, __pte);                                  \
-})
+#define pte_alloc_one_kernel(mm, vmaddr) \
+       ((pte_t *) page_table_alloc(s390_noexec))
+#define pte_alloc_one(mm, vmaddr) \
+       virt_to_page(page_table_alloc(s390_noexec))
+
+#define pte_free_kernel(pte) \
+       page_table_free((unsigned long *) pte)
+#define pte_free(pte) \
+       page_table_free((unsigned long *) page_to_phys((struct page *) pte))
 
 #endif /* _S390_PGALLOC_H */
index 39bb519..f2cc25b 100644 (file)
@@ -13,8 +13,6 @@
 #ifndef _ASM_S390_PGTABLE_H
 #define _ASM_S390_PGTABLE_H
 
-#include <asm-generic/4level-fixup.h>
-
 /*
  * The Linux memory management assumes a three-level page table setup. For
  * s390 31 bit we "fold" the mid level into the top-level page table, so
@@ -35,9 +33,6 @@
 #include <asm/bug.h>
 #include <asm/processor.h>
 
-struct vm_area_struct; /* forward declaration (include/linux/mm.h) */
-struct mm_struct;
-
 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
 extern void paging_init(void);
 extern void vmem_map_init(void);
@@ -63,14 +58,18 @@ extern char empty_zero_page[PAGE_SIZE];
  */
 #ifndef __s390x__
 # define PMD_SHIFT     22
+# define PUD_SHIFT     22
 # define PGDIR_SHIFT   22
 #else /* __s390x__ */
 # define PMD_SHIFT     21
+# define PUD_SHIFT     31
 # define PGDIR_SHIFT   31
 #endif /* __s390x__ */
 
 #define PMD_SIZE        (1UL << PMD_SHIFT)
 #define PMD_MASK        (~(PMD_SIZE-1))
+#define PUD_SIZE       (1UL << PUD_SHIFT)
+#define PUD_MASK       (~(PUD_SIZE-1))
 #define PGDIR_SIZE      (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK      (~(PGDIR_SIZE-1))
 
@@ -83,10 +82,12 @@ extern char empty_zero_page[PAGE_SIZE];
 #ifndef __s390x__
 # define PTRS_PER_PTE    1024
 # define PTRS_PER_PMD    1
+# define PTRS_PER_PUD  1
 # define PTRS_PER_PGD    512
 #else /* __s390x__ */
 # define PTRS_PER_PTE    512
 # define PTRS_PER_PMD    1024
+# define PTRS_PER_PUD  1
 # define PTRS_PER_PGD    2048
 #endif /* __s390x__ */
 
@@ -96,6 +97,8 @@ extern char empty_zero_page[PAGE_SIZE];
        printk("%s:%d: bad pte %p.\n", __FILE__, __LINE__, (void *) pte_val(e))
 #define pmd_ERROR(e) \
        printk("%s:%d: bad pmd %p.\n", __FILE__, __LINE__, (void *) pmd_val(e))
+#define pud_ERROR(e) \
+       printk("%s:%d: bad pud %p.\n", __FILE__, __LINE__, (void *) pud_val(e))
 #define pgd_ERROR(e) \
        printk("%s:%d: bad pgd %p.\n", __FILE__, __LINE__, (void *) pgd_val(e))
 
@@ -195,7 +198,7 @@ extern unsigned long vmalloc_end;
  * I Segment-Invalid Bit:    Segment is not available for address-translation
  * TT Type 01
  * TF
- * TL Table lenght
+ * TL Table length
  *
  * The 64 bit regiontable origin of S390 has following format:
  * |      region table origon                          |       DTTL
@@ -221,6 +224,8 @@ extern unsigned long vmalloc_end;
 /* Hardware bits in the page table entry */
 #define _PAGE_RO       0x200           /* HW read-only bit  */
 #define _PAGE_INVALID  0x400           /* HW invalid bit    */
+
+/* Software bits in the page table entry */
 #define _PAGE_SWT      0x001           /* SW pte type bit t */
 #define _PAGE_SWX      0x002           /* SW pte type bit x */
 
@@ -264,60 +269,75 @@ extern unsigned long vmalloc_end;
 
 #ifndef __s390x__
 
-/* Bits in the segment table entry */
-#define _PAGE_TABLE_LEN 0xf            /* only full page-tables            */
-#define _PAGE_TABLE_COM 0x10           /* common page-table                */
-#define _PAGE_TABLE_INV 0x20           /* invalid page-table               */
-#define _SEG_PRESENT    0x001          /* Software (overlap with PTL)      */
-
-/* Bits int the storage key */
-#define _PAGE_CHANGED    0x02          /* HW changed bit                   */
-#define _PAGE_REFERENCED 0x04          /* HW referenced bit                */
-
-#define _USER_SEG_TABLE_LEN    0x7f    /* user-segment-table up to 2 GB    */
-#define _KERNEL_SEG_TABLE_LEN  0x7f    /* kernel-segment-table up to 2 GB  */
-
-/*
- * User and Kernel pagetables are identical
- */
-#define _PAGE_TABLE    _PAGE_TABLE_LEN
-#define _KERNPG_TABLE  _PAGE_TABLE_LEN
-
-/*
- * The Kernel segment-tables includes the User segment-table
- */
+/* Bits in the segment table address-space-control-element */
+#define _ASCE_SPACE_SWITCH     0x80000000UL    /* space switch event       */
+#define _ASCE_ORIGIN_MASK      0x7ffff000UL    /* segment table origin     */
+#define _ASCE_PRIVATE_SPACE    0x100   /* private space control            */
+#define _ASCE_ALT_EVENT                0x80    /* storage alteration event control */
+#define _ASCE_TABLE_LENGTH     0x7f    /* 128 x 64 entries = 8k            */
 
-#define _SEGMENT_TABLE (_USER_SEG_TABLE_LEN|0x80000000|0x100)
-#define _KERNSEG_TABLE _KERNEL_SEG_TABLE_LEN
+/* Bits in the segment table entry */
+#define _SEGMENT_ENTRY_ORIGIN  0x7fffffc0UL    /* page table origin        */
+#define _SEGMENT_ENTRY_INV     0x20    /* invalid segment table entry      */
+#define _SEGMENT_ENTRY_COMMON  0x10    /* common segment bit               */
+#define _SEGMENT_ENTRY_PTL     0x0f    /* page table length                */
 
-#define USER_STD_MASK  0x00000080UL
+#define _SEGMENT_ENTRY         (_SEGMENT_ENTRY_PTL)
+#define _SEGMENT_ENTRY_EMPTY   (_SEGMENT_ENTRY_INV)
 
 #else /* __s390x__ */
 
+/* Bits in the segment/region table address-space-control-element */
+#define _ASCE_ORIGIN           ~0xfffUL/* segment table origin             */
+#define _ASCE_PRIVATE_SPACE    0x100   /* private space control            */
+#define _ASCE_ALT_EVENT                0x80    /* storage alteration event control */
+#define _ASCE_SPACE_SWITCH     0x40    /* space switch event               */
+#define _ASCE_REAL_SPACE       0x20    /* real space control               */
+#define _ASCE_TYPE_MASK                0x0c    /* asce table type mask             */
+#define _ASCE_TYPE_REGION1     0x0c    /* region first table type          */
+#define _ASCE_TYPE_REGION2     0x08    /* region second table type         */
+#define _ASCE_TYPE_REGION3     0x04    /* region third table type          */
+#define _ASCE_TYPE_SEGMENT     0x00    /* segment table type               */
+#define _ASCE_TABLE_LENGTH     0x03    /* region table length              */
+
+/* Bits in the region table entry */
+#define _REGION_ENTRY_ORIGIN   ~0xfffUL/* region/segment table origin      */
+#define _REGION_ENTRY_INV      0x20    /* invalid region table entry       */
+#define _REGION_ENTRY_TYPE_MASK        0x0c    /* region/segment table type mask   */
+#define _REGION_ENTRY_TYPE_R1  0x0c    /* region first table type          */
+#define _REGION_ENTRY_TYPE_R2  0x08    /* region second table type         */
+#define _REGION_ENTRY_TYPE_R3  0x04    /* region third table type          */
+#define _REGION_ENTRY_LENGTH   0x03    /* region third length              */
+
+#define _REGION1_ENTRY         (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_LENGTH)
+#define _REGION1_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INV)
+#define _REGION2_ENTRY         (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_LENGTH)
+#define _REGION2_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INV)
+#define _REGION3_ENTRY         (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH)
+#define _REGION3_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV)
+
 /* Bits in the segment table entry */
-#define _PMD_ENTRY_INV   0x20          /* invalid segment table entry      */
-#define _PMD_ENTRY       0x00        
+#define _SEGMENT_ENTRY_ORIGIN  ~0x7ffUL/* segment table origin             */
+#define _SEGMENT_ENTRY_RO      0x200   /* page protection bit              */
+#define _SEGMENT_ENTRY_INV     0x20    /* invalid segment table entry      */
+
+#define _SEGMENT_ENTRY         (0)
+#define _SEGMENT_ENTRY_EMPTY   (_SEGMENT_ENTRY_INV)
 
-/* Bits in the region third table entry */
-#define _PGD_ENTRY_INV   0x20          /* invalid region table entry       */
-#define _PGD_ENTRY       0x07
+#endif /* __s390x__ */
 
 /*
- * User and kernel page directory
+ * A user page table pointer has the space-switch-event bit, the
+ * private-space-control bit and the storage-alteration-event-control
+ * bit set. A kernel page table pointer doesn't need them.
  */
-#define _REGION_THIRD       0x4
-#define _REGION_THIRD_LEN   0x3 
-#define _REGION_TABLE       (_REGION_THIRD|_REGION_THIRD_LEN|0x40|0x100)
-#define _KERN_REGION_TABLE  (_REGION_THIRD|_REGION_THIRD_LEN)
-
-#define USER_STD_MASK           0x0000000000000080UL
+#define _ASCE_USER_BITS                (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \
+                                _ASCE_ALT_EVENT)
 
-/* Bits in the storage key */
+/* Bits int the storage key */
 #define _PAGE_CHANGED    0x02          /* HW changed bit                   */
 #define _PAGE_REFERENCED 0x04          /* HW referenced bit                */
 
-#endif /* __s390x__ */
-
 /*
  * Page protection definitions.
  */
@@ -358,65 +378,38 @@ extern unsigned long vmalloc_end;
 #define __S111 PAGE_EX_RW
 
 #ifndef __s390x__
-# define PMD_SHADOW_SHIFT      1
-# define PGD_SHADOW_SHIFT      1
+# define PxD_SHADOW_SHIFT      1
 #else /* __s390x__ */
-# define PMD_SHADOW_SHIFT      2
-# define PGD_SHADOW_SHIFT      2
+# define PxD_SHADOW_SHIFT      2
 #endif /* __s390x__ */
 
 static inline struct page *get_shadow_page(struct page *page)
 {
-       if (s390_noexec && !list_empty(&page->lru))
-               return virt_to_page(page->lru.next);
-       return NULL;
-}
-
-static inline pte_t *get_shadow_pte(pte_t *ptep)
-{
-       unsigned long pteptr = (unsigned long) (ptep);
-
-       if (s390_noexec) {
-               unsigned long offset = pteptr & (PAGE_SIZE - 1);
-               void *addr = (void *) (pteptr ^ offset);
-               struct page *page = virt_to_page(addr);
-               if (!list_empty(&page->lru))
-                       return (pte_t *) ((unsigned long) page->lru.next |
-                                                               offset);
-       }
+       if (s390_noexec && page->index)
+               return virt_to_page((void *)(addr_t) page->index);
        return NULL;
 }
 
-static inline pmd_t *get_shadow_pmd(pmd_t *pmdp)
+static inline void *get_shadow_pte(void *table)
 {
-       unsigned long pmdptr = (unsigned long) (pmdp);
+       unsigned long addr, offset;
+       struct page *page;
 
-       if (s390_noexec) {
-               unsigned long offset = pmdptr &
-                               ((PAGE_SIZE << PMD_SHADOW_SHIFT) - 1);
-               void *addr = (void *) (pmdptr ^ offset);
-               struct page *page = virt_to_page(addr);
-               if (!list_empty(&page->lru))
-                       return (pmd_t *) ((unsigned long) page->lru.next |
-                                                               offset);
-       }
-       return NULL;
+       addr = (unsigned long) table;
+       offset = addr & (PAGE_SIZE - 1);
+       page = virt_to_page((void *)(addr ^ offset));
+       return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL);
 }
 
-static inline pgd_t *get_shadow_pgd(pgd_t *pgdp)
+static inline void *get_shadow_table(void *table)
 {
-       unsigned long pgdptr = (unsigned long) (pgdp);
+       unsigned long addr, offset;
+       struct page *page;
 
-       if (s390_noexec) {
-               unsigned long offset = pgdptr &
-                               ((PAGE_SIZE << PGD_SHADOW_SHIFT) - 1);
-               void *addr = (void *) (pgdptr ^ offset);
-               struct page *page = virt_to_page(addr);
-               if (!list_empty(&page->lru))
-                       return (pgd_t *) ((unsigned long) page->lru.next |
-                                                               offset);
-       }
-       return NULL;
+       addr = (unsigned long) table;
+       offset = addr & ((PAGE_SIZE << PxD_SHADOW_SHIFT) - 1);
+       page = virt_to_page((void *)(addr ^ offset));
+       return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL);
 }
 
 /*
@@ -424,7 +417,8 @@ static inline pgd_t *get_shadow_pgd(pgd_t *pgdp)
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
-static inline void set_pte(pte_t *pteptr, pte_t pteval)
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *pteptr, pte_t pteval)
 {
        pte_t *shadow_pte = get_shadow_pte(pteptr);
 
@@ -437,7 +431,6 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval)
                        pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY;
        }
 }
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
 /*
  * pgd/pmd/pte query functions
@@ -448,47 +441,50 @@ static inline int pgd_present(pgd_t pgd) { return 1; }
 static inline int pgd_none(pgd_t pgd)    { return 0; }
 static inline int pgd_bad(pgd_t pgd)     { return 0; }
 
-static inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; }
-static inline int pmd_none(pmd_t pmd)    { return pmd_val(pmd) & _PAGE_TABLE_INV; }
-static inline int pmd_bad(pmd_t pmd)
-{
-       return (pmd_val(pmd) & (~PAGE_MASK & ~_PAGE_TABLE_INV)) != _PAGE_TABLE;
-}
+static inline int pud_present(pud_t pud) { return 1; }
+static inline int pud_none(pud_t pud)   { return 0; }
+static inline int pud_bad(pud_t pud)    { return 0; }
 
 #else /* __s390x__ */
 
-static inline int pgd_present(pgd_t pgd)
+static inline int pgd_present(pgd_t pgd) { return 1; }
+static inline int pgd_none(pgd_t pgd)   { return 0; }
+static inline int pgd_bad(pgd_t pgd)    { return 0; }
+
+static inline int pud_present(pud_t pud)
 {
-       return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY;
+       return pud_val(pud) & _REGION_ENTRY_ORIGIN;
 }
 
-static inline int pgd_none(pgd_t pgd)
+static inline int pud_none(pud_t pud)
 {
-       return pgd_val(pgd) & _PGD_ENTRY_INV;
+       return pud_val(pud) & _REGION_ENTRY_INV;
 }
 
-static inline int pgd_bad(pgd_t pgd)
+static inline int pud_bad(pud_t pud)
 {
-       return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY;
+       unsigned long mask = ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV;
+       return (pud_val(pud) & mask) != _REGION3_ENTRY;
 }
 
+#endif /* __s390x__ */
+
 static inline int pmd_present(pmd_t pmd)
 {
-       return (pmd_val(pmd) & ~PAGE_MASK) == _PMD_ENTRY;
+       return pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN;
 }
 
 static inline int pmd_none(pmd_t pmd)
 {
-       return pmd_val(pmd) & _PMD_ENTRY_INV;
+       return pmd_val(pmd) & _SEGMENT_ENTRY_INV;
 }
 
 static inline int pmd_bad(pmd_t pmd)
 {
-       return (pmd_val(pmd) & (~PAGE_MASK & ~_PMD_ENTRY_INV)) != _PMD_ENTRY;
+       unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INV;
+       return (pmd_val(pmd) & mask) != _SEGMENT_ENTRY;
 }
 
-#endif /* __s390x__ */
-
 static inline int pte_none(pte_t pte)
 {
        return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT);
@@ -508,7 +504,8 @@ static inline int pte_file(pte_t pte)
        return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
 }
 
-#define pte_same(a,b)  (pte_val(a) == pte_val(b))
+#define __HAVE_ARCH_PTE_SAME
+#define pte_same(a,b)  (pte_val(a) == pte_val(b))
 
 /*
  * query functions pte_write/pte_dirty/pte_young only work if
@@ -543,58 +540,52 @@ static inline int pte_young(pte_t pte)
 
 #ifndef __s390x__
 
-static inline void pgd_clear(pgd_t * pgdp)      { }
+#define pgd_clear(pgd)         do { } while (0)
+#define pud_clear(pud)         do { } while (0)
 
 static inline void pmd_clear_kernel(pmd_t * pmdp)
 {
-       pmd_val(pmdp[0]) = _PAGE_TABLE_INV;
-       pmd_val(pmdp[1]) = _PAGE_TABLE_INV;
-       pmd_val(pmdp[2]) = _PAGE_TABLE_INV;
-       pmd_val(pmdp[3]) = _PAGE_TABLE_INV;
-}
-
-static inline void pmd_clear(pmd_t * pmdp)
-{
-       pmd_t *shadow_pmd = get_shadow_pmd(pmdp);
-
-       pmd_clear_kernel(pmdp);
-       if (shadow_pmd)
-               pmd_clear_kernel(shadow_pmd);
+       pmd_val(pmdp[0]) = _SEGMENT_ENTRY_EMPTY;
+       pmd_val(pmdp[1]) = _SEGMENT_ENTRY_EMPTY;
+       pmd_val(pmdp[2]) = _SEGMENT_ENTRY_EMPTY;
+       pmd_val(pmdp[3]) = _SEGMENT_ENTRY_EMPTY;
 }
 
 #else /* __s390x__ */
 
-static inline void pgd_clear_kernel(pgd_t * pgdp)
+#define pgd_clear(pgd)         do { } while (0)
+
+static inline void pud_clear_kernel(pud_t *pud)
 {
-       pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY;
+       pud_val(*pud) = _REGION3_ENTRY_EMPTY;
 }
 
-static inline void pgd_clear(pgd_t * pgdp)
+static inline void pud_clear(pud_t * pud)
 {
-       pgd_t *shadow_pgd = get_shadow_pgd(pgdp);
+       pud_t *shadow = get_shadow_table(pud);
 
-       pgd_clear_kernel(pgdp);
-       if (shadow_pgd)
-               pgd_clear_kernel(shadow_pgd);
+       pud_clear_kernel(pud);
+       if (shadow)
+               pud_clear_kernel(shadow);
 }
 
 static inline void pmd_clear_kernel(pmd_t * pmdp)
 {
-       pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
-       pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
+       pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY;
+       pmd_val1(*pmdp) = _SEGMENT_ENTRY_EMPTY;
 }
 
+#endif /* __s390x__ */
+
 static inline void pmd_clear(pmd_t * pmdp)
 {
-       pmd_t *shadow_pmd = get_shadow_pmd(pmdp);
+       pmd_t *shadow_pmd = get_shadow_table(pmdp);
 
        pmd_clear_kernel(pmdp);
        if (shadow_pmd)
                pmd_clear_kernel(shadow_pmd);
 }
 
-#endif /* __s390x__ */
-
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
        pte_t *shadow_pte = get_shadow_pte(ptep);
@@ -663,24 +654,19 @@ static inline pte_t pte_mkyoung(pte_t pte)
        return pte;
 }
 
-static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
+                                           unsigned long addr, pte_t *ptep)
 {
        return 0;
 }
 
-static inline int
-ptep_clear_flush_young(struct vm_area_struct *vma,
-                       unsigned long address, pte_t *ptep)
+#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
+static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
+                                        unsigned long address, pte_t *ptep)
 {
        /* No need to flush TLB; bits are in storage key */
-       return ptep_test_and_clear_young(vma, address, ptep);
-}
-
-static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-       pte_t pte = *ptep;
-       pte_clear(mm, addr, ptep);
-       return pte;
+       return 0;
 }
 
 static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
@@ -709,6 +695,32 @@ static inline void ptep_invalidate(unsigned long address, pte_t *ptep)
                __ptep_ipte(address, ptep);
 }
 
+/*
+ * This is hard to understand. ptep_get_and_clear and ptep_clear_flush
+ * both clear the TLB for the unmapped pte. The reason is that
+ * ptep_get_and_clear is used in common code (e.g. change_pte_range)
+ * to modify an active pte. The sequence is
+ *   1) ptep_get_and_clear
+ *   2) set_pte_at
+ *   3) flush_tlb_range
+ * On s390 the tlb needs to get flushed with the modification of the pte
+ * if the pte is active. The only way how this can be implemented is to
+ * have ptep_get_and_clear do the tlb flush. In exchange flush_tlb_range
+ * is a nop.
+ */
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define ptep_get_and_clear(__mm, __address, __ptep)                    \
+({                                                                     \
+       pte_t __pte = *(__ptep);                                        \
+       if (atomic_read(&(__mm)->mm_users) > 1 ||                       \
+           (__mm) != current->active_mm)                               \
+               ptep_invalidate(__address, __ptep);                     \
+       else                                                            \
+               pte_clear((__mm), (__address), (__ptep));               \
+       __pte;                                                          \
+})
+
+#define __HAVE_ARCH_PTEP_CLEAR_FLUSH
 static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
                                     unsigned long address, pte_t *ptep)
 {
@@ -717,12 +729,40 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
        return pte;
 }
 
-static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+/*
+ * The batched pte unmap code uses ptep_get_and_clear_full to clear the
+ * ptes. Here an optimization is possible. tlb_gather_mmu flushes all
+ * tlbs of an mm if it can guarantee that the ptes of the mm_struct
+ * cannot be accessed while the batched unmap is running. In this case
+ * full==1 and a simple pte_clear is enough. See tlb.h.
+ */
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
+static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
+                                           unsigned long addr,
+                                           pte_t *ptep, int full)
 {
-       pte_t old_pte = *ptep;
-       set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
+       pte_t pte = *ptep;
+
+       if (full)
+               pte_clear(mm, addr, ptep);
+       else
+               ptep_invalidate(addr, ptep);
+       return pte;
 }
 
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+#define ptep_set_wrprotect(__mm, __addr, __ptep)                       \
+({                                                                     \
+       pte_t __pte = *(__ptep);                                        \
+       if (pte_write(__pte)) {                                         \
+               if (atomic_read(&(__mm)->mm_users) > 1 ||               \
+                   (__mm) != current->active_mm)                       \
+                       ptep_invalidate(__addr, __ptep);                \
+               set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \
+       }                                                               \
+})
+
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 #define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
 ({                                                                     \
        int __changed = !pte_same(*(__ptep), __entry);                  \
@@ -740,11 +780,13 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
  * should therefore only be called if it is not mapped in any
  * address space.
  */
+#define __HAVE_ARCH_PAGE_TEST_DIRTY
 static inline int page_test_dirty(struct page *page)
 {
        return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0;
 }
 
+#define __HAVE_ARCH_PAGE_CLEAR_DIRTY
 static inline void page_clear_dirty(struct page *page)
 {
        page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY);
@@ -753,6 +795,7 @@ static inline void page_clear_dirty(struct page *page)
 /*
  * Test and clear referenced bit in storage key.
  */
+#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
 static inline int page_test_and_clear_young(struct page *page)
 {
        unsigned long physpage = page_to_phys(page);
@@ -784,63 +827,48 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
        return mk_pte_phys(physpage, pgprot);
 }
 
-static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
-{
-       unsigned long physpage = __pa((pfn) << PAGE_SHIFT);
-
-       return mk_pte_phys(physpage, pgprot);
-}
-
-#ifdef __s390x__
-
-static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot)
-{
-       unsigned long physpage = __pa((pfn) << PAGE_SHIFT);
-
-       return __pmd(physpage + pgprot_val(pgprot));
-}
-
-#endif /* __s390x__ */
-
-#define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT)
-#define pte_page(x) pfn_to_page(pte_pfn(x))
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
+#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1))
 
-#define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK)
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-#define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)
+#ifndef __s390x__
 
-#define pgd_page_vaddr(pgd) (pgd_val(pgd) & PAGE_MASK)
+#define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN)
+#define pud_deref(pmd) ({ BUG(); 0UL; })
+#define pgd_deref(pmd) ({ BUG(); 0UL; })
 
-#define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT)
+#define pud_offset(pgd, address) ((pud_t *) pgd)
+#define pmd_offset(pud, address) ((pmd_t *) pud + pmd_index(address))
 
-/* to find an entry in a page-table-directory */
-#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
+#else /* __s390x__ */
 
-/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+#define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN)
+#define pud_deref(pud) (pud_val(pud) & _REGION_ENTRY_ORIGIN)
+#define pgd_deref(pgd) ({ BUG(); 0UL; })
 
-#ifndef __s390x__
+#define pud_offset(pgd, address) ((pud_t *) pgd)
 
-/* Find an entry in the second-level page table.. */
-static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
 {
-        return (pmd_t *) dir;
+       pmd_t *pmd = (pmd_t *) pud_deref(*pud);
+       return pmd + pmd_index(address);
 }
 
-#else /* __s390x__ */
+#endif /* __s390x__ */
 
-/* Find an entry in the second-level page table.. */
-#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
-#define pmd_offset(dir,addr) \
-       ((pmd_t *) pgd_page_vaddr(*(dir)) + pmd_index(addr))
+#define pfn_pte(pfn,pgprot) mk_pte_phys(__pa((pfn) << PAGE_SHIFT),(pgprot))
+#define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT)
+#define pte_page(x) pfn_to_page(pte_pfn(x))
 
-#endif /* __s390x__ */
+#define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)
 
-/* Find an entry in the third-level page table.. */
-#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1))
-#define pte_offset_kernel(pmd, address) \
-       ((pte_t *) pmd_page_vaddr(*(pmd)) + pte_index(address))
+/* Find an entry in the lowest level page table.. */
+#define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr))
+#define pte_offset_kernel(pmd, address) pte_offset(pmd,address)
 #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
 #define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
 #define pte_unmap(pte) do { } while (0)
@@ -930,17 +958,6 @@ extern int remove_shared_memory(unsigned long start, unsigned long size);
 #define __HAVE_ARCH_MEMMAP_INIT
 extern void memmap_init(unsigned long, int, unsigned long, unsigned long);
 
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-#define __HAVE_ARCH_PTEP_CLEAR_FLUSH
-#define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTE_SAME
-#define __HAVE_ARCH_PAGE_TEST_DIRTY
-#define __HAVE_ARCH_PAGE_CLEAR_DIRTY
-#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
 #include <asm-generic/pgtable.h>
 
 #endif /* _S390_PAGE_H */
-
index 3b972d4..21d40a1 100644 (file)
@@ -93,7 +93,6 @@ struct thread_struct {
        s390_fp_regs fp_regs;
        unsigned int  acrs[NUM_ACRS];
         unsigned long ksp;              /* kernel stack pointer             */
-        unsigned long user_seg;         /* HSTD                             */
        mm_segment_t mm_segment;
         unsigned long prot_addr;        /* address of protection-excep.     */
         unsigned int error_code;        /* error-code of last prog-excep.   */
@@ -128,22 +127,9 @@ struct stack_frame {
 
 #define ARCH_MIN_TASKALIGN     8
 
-#ifndef __s390x__
-# define __SWAPPER_PG_DIR __pa(&swapper_pg_dir[0]) + _SEGMENT_TABLE
-#else /* __s390x__ */
-# define __SWAPPER_PG_DIR __pa(&swapper_pg_dir[0]) + _REGION_TABLE
-#endif /* __s390x__ */
-
-#define INIT_THREAD {{0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},             \
-                           {0},{0},{0},{0},{0},{0}}},                         \
-                    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},         \
-                    sizeof(init_stack) + (unsigned long) &init_stack,         \
-                    __SWAPPER_PG_DIR,                                         \
-                    {0},                                                      \
-                    0,0,0,                                                    \
-                    (per_struct) {{{{0,}}},0,0,0,0,{{0,}}},                   \
-                    0, 0                                                      \
-} 
+#define INIT_THREAD {                                                  \
+       .ksp = sizeof(init_stack) + (unsigned long) &init_stack,        \
+}
 
 /*
  * Do necessary setup to start up a new thread.
index a43b3af..29ec8e2 100644 (file)
@@ -2,7 +2,10 @@
 #define _ASMS390_SCATTERLIST_H
 
 struct scatterlist {
-    struct page *page;
+#ifdef CONFIG_DEBUG_SG
+    unsigned long sg_magic;
+#endif
+    unsigned long page_link;
     unsigned int offset;
     unsigned int length;
 };
index 51bd957..618693c 100644 (file)
 #define _S390_TLB_H
 
 /*
- * s390 doesn't need any special per-pte or
- * per-vma handling..
+ * TLB flushing on s390 is complicated. The following requirement
+ * from the principles of operation is the most arduous:
+ *
+ * "A valid table entry must not be changed while it is attached
+ * to any CPU and may be used for translation by that CPU except to
+ * (1) invalidate the entry by using INVALIDATE PAGE TABLE ENTRY,
+ * or INVALIDATE DAT TABLE ENTRY, (2) alter bits 56-63 of a page
+ * table entry, or (3) make a change by means of a COMPARE AND SWAP
+ * AND PURGE instruction that purges the TLB."
+ *
+ * The modification of a pte of an active mm struct therefore is
+ * a two step process: i) invalidate the pte, ii) store the new pte.
+ * This is true for the page protection bit as well.
+ * The only possible optimization is to flush at the beginning of
+ * a tlb_gather_mmu cycle if the mm_struct is currently not in use.
+ *
+ * Pages used for the page tables is a different story. FIXME: more
  */
-#define tlb_start_vma(tlb, vma) do { } while (0)
-#define tlb_end_vma(tlb, vma) do { } while (0)
-#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
+
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <asm/processor.h>
+#include <asm/pgalloc.h>
+#include <asm/smp.h>
+#include <asm/tlbflush.h>
+
+#ifndef CONFIG_SMP
+#define TLB_NR_PTRS    1
+#else
+#define TLB_NR_PTRS    508
+#endif
+
+struct mmu_gather {
+       struct mm_struct *mm;
+       unsigned int fullmm;
+       unsigned int nr_ptes;
+       unsigned int nr_pmds;
+       void *array[TLB_NR_PTRS];
+};
+
+DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm,
+                                               unsigned int full_mm_flush)
+{
+       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+
+       tlb->mm = mm;
+       tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) ||
+               (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm);
+       tlb->nr_ptes = 0;
+       tlb->nr_pmds = TLB_NR_PTRS;
+       if (tlb->fullmm)
+               __tlb_flush_mm(mm);
+       return tlb;
+}
+
+static inline void tlb_flush_mmu(struct mmu_gather *tlb,
+                                unsigned long start, unsigned long end)
+{
+       if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pmds < TLB_NR_PTRS))
+               __tlb_flush_mm(tlb->mm);
+       while (tlb->nr_ptes > 0)
+               pte_free(tlb->array[--tlb->nr_ptes]);
+       while (tlb->nr_pmds < TLB_NR_PTRS)
+               pmd_free((pmd_t *) tlb->array[tlb->nr_pmds++]);
+}
+
+static inline void tlb_finish_mmu(struct mmu_gather *tlb,
+                                 unsigned long start, unsigned long end)
+{
+       tlb_flush_mmu(tlb, start, end);
+
+       /* keep the page table cache within bounds */
+       check_pgt_cache();
+
+       put_cpu_var(mmu_gathers);
+}
 
 /*
- * .. because we flush the whole mm when it
- * fills up.
+ * Release the page cache reference for a pte removed by
+ * tlb_ptep_clear_flush. In both flush modes the tlb fo a page cache page
+ * has already been freed, so just do free_page_and_swap_cache.
  */
-#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       free_page_and_swap_cache(page);
+}
 
-#include <asm-generic/tlb.h>
+/*
+ * pte_free_tlb frees a pte table and clears the CRSTE for the
+ * page table from the tlb.
+ */
+static inline void pte_free_tlb(struct mmu_gather *tlb, struct page *page)
+{
+       if (!tlb->fullmm) {
+               tlb->array[tlb->nr_ptes++] = page;
+               if (tlb->nr_ptes >= tlb->nr_pmds)
+                       tlb_flush_mmu(tlb, 0, 0);
+       } else
+               pte_free(page);
+}
 
+/*
+ * pmd_free_tlb frees a pmd table and clears the CRSTE for the
+ * segment table entry from the tlb.
+ */
+static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+{
+#ifdef __s390x__
+       if (!tlb->fullmm) {
+               tlb->array[--tlb->nr_pmds] = (struct page *) pmd;
+               if (tlb->nr_ptes >= tlb->nr_pmds)
+                       tlb_flush_mmu(tlb, 0, 0);
+       } else
+               pmd_free(pmd);
 #endif
+}
+
+#define pud_free_tlb(tlb, pud)                 do { } while (0)
+
+#define tlb_start_vma(tlb, vma)                        do { } while (0)
+#define tlb_end_vma(tlb, vma)                  do { } while (0)
+#define tlb_remove_tlb_entry(tlb, ptep, addr)  do { } while (0)
+#define tlb_migrate_finish(mm)                 do { } while (0)
+
+#endif /* _S390_TLB_H */
index 6de2632..a69bd24 100644 (file)
@@ -6,68 +6,19 @@
 #include <asm/pgalloc.h>
 
 /*
- * TLB flushing:
- *
- *  - flush_tlb() flushes the current mm struct TLBs
- *  - flush_tlb_all() flushes all processes TLBs 
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(vma, start, end) flushes a range of pages
- *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
- */
-
-/*
- * S/390 has three ways of flushing TLBs
- * 'ptlb' does a flush of the local processor
- * 'csp' flushes the TLBs on all PUs of a SMP
- * 'ipte' invalidates a pte in a page table and flushes that out of
- * the TLBs of all PUs of a SMP
- */
-
-#define local_flush_tlb() \
-do {  asm volatile("ptlb": : :"memory"); } while (0)
-
-#ifndef CONFIG_SMP
-
-/*
- * We always need to flush, since s390 does not flush tlb
- * on each context switch
+ * Flush all tlb entries on the local cpu.
  */
-
-static inline void flush_tlb(void)
+static inline void __tlb_flush_local(void)
 {
-       local_flush_tlb();
+       asm volatile("ptlb" : : : "memory");
 }
-static inline void flush_tlb_all(void)
-{
-       local_flush_tlb();
-}
-static inline void flush_tlb_mm(struct mm_struct *mm) 
-{
-       local_flush_tlb();
-}
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-                                 unsigned long addr)
-{
-       local_flush_tlb();
-}
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-                                  unsigned long start, unsigned long end)
-{
-       local_flush_tlb();
-}
-
-#define flush_tlb_kernel_range(start, end) \
-       local_flush_tlb();
-
-#else
 
-#include <asm/smp.h>
-
-extern void smp_ptlb_all(void);
-
-static inline void global_flush_tlb(void)
+/*
+ * Flush all tlb entries on all cpus.
+ */
+static inline void __tlb_flush_global(void)
 {
+       extern void smp_ptlb_all(void);
        register unsigned long reg2 asm("2");
        register unsigned long reg3 asm("3");
        register unsigned long reg4 asm("4");
@@ -89,66 +40,75 @@ static inline void global_flush_tlb(void)
 }
 
 /*
- * We only have to do global flush of tlb if process run since last
- * flush on any other pu than current. 
- * If we have threads (mm->count > 1) we always do a global flush, 
- * since the process runs on more than one processor at the same time.
+ * Flush all tlb entries of a page table on all cpus.
  */
+static inline void __tlb_flush_idte(pgd_t *pgd)
+{
+       asm volatile(
+               "       .insn   rrf,0xb98e0000,0,%0,%1,0"
+               : : "a" (2048), "a" (__pa(pgd) & PAGE_MASK) : "cc" );
+}
 
-static inline void __flush_tlb_mm(struct mm_struct * mm)
+static inline void __tlb_flush_mm(struct mm_struct * mm)
 {
        cpumask_t local_cpumask;
 
        if (unlikely(cpus_empty(mm->cpu_vm_mask)))
                return;
+       /*
+        * If the machine has IDTE we prefer to do a per mm flush
+        * on all cpus instead of doing a local flush if the mm
+        * only ran on the local cpu.
+        */
        if (MACHINE_HAS_IDTE) {
-               pgd_t *shadow_pgd = get_shadow_pgd(mm->pgd);
+               pgd_t *shadow_pgd = get_shadow_table(mm->pgd);
 
-               if (shadow_pgd) {
-                       asm volatile(
-                               "       .insn   rrf,0xb98e0000,0,%0,%1,0"
-                               : : "a" (2048),
-                               "a" (__pa(shadow_pgd) & PAGE_MASK) : "cc" );
-               }
-               asm volatile(
-                       "       .insn   rrf,0xb98e0000,0,%0,%1,0"
-                       : : "a" (2048), "a" (__pa(mm->pgd)&PAGE_MASK) : "cc");
+               if (shadow_pgd)
+                       __tlb_flush_idte(shadow_pgd);
+               __tlb_flush_idte(mm->pgd);
                return;
        }
        preempt_disable();
+       /*
+        * If the process only ran on the local cpu, do a local flush.
+        */
        local_cpumask = cpumask_of_cpu(smp_processor_id());
        if (cpus_equal(mm->cpu_vm_mask, local_cpumask))
-               local_flush_tlb();
+               __tlb_flush_local();
        else
-               global_flush_tlb();
+               __tlb_flush_global();
        preempt_enable();
 }
 
-static inline void flush_tlb(void)
-{
-       __flush_tlb_mm(current->mm);
-}
-static inline void flush_tlb_all(void)
-{
-       global_flush_tlb();
-}
-static inline void flush_tlb_mm(struct mm_struct *mm) 
-{
-       __flush_tlb_mm(mm); 
-}
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-                                 unsigned long addr)
-{
-       __flush_tlb_mm(vma->vm_mm);
-}
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-                                  unsigned long start, unsigned long end)
+static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
 {
-       __flush_tlb_mm(vma->vm_mm); 
+       if (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm)
+               __tlb_flush_mm(mm);
 }
 
-#define flush_tlb_kernel_range(start, end) global_flush_tlb()
+/*
+ * TLB flushing:
+ *  flush_tlb() - flushes the current mm struct TLBs
+ *  flush_tlb_all() - flushes all processes TLBs
+ *  flush_tlb_mm(mm) - flushes the specified mm context TLB's
+ *  flush_tlb_page(vma, vmaddr) - flushes one page
+ *  flush_tlb_range(vma, start, end) - flushes a range of pages
+ *  flush_tlb_kernel_range(start, end) - flushes a range of kernel pages
+ */
 
-#endif
+/*
+ * flush_tlb_mm goes together with ptep_set_wrprotect for the
+ * copy_page_range operation and flush_tlb_range is related to
+ * ptep_get_and_clear for change_protection. ptep_set_wrprotect and
+ * ptep_get_and_clear do not flush the TLBs directly if the mm has
+ * only one user. At the end of the update the flush_tlb_mm and
+ * flush_tlb_range functions need to do the flush.
+ */
+#define flush_tlb()                            do { } while (0)
+#define flush_tlb_all()                                do { } while (0)
+#define flush_tlb_mm(mm)                       __tlb_flush_mm_cond(mm)
+#define flush_tlb_page(vma, addr)              do { } while (0)
+#define flush_tlb_range(vma, start, end)       __tlb_flush_mm_cond(mm)
+#define flush_tlb_kernel_range(start, end)     __tlb_flush_mm(&init_mm)
 
 #endif /* _S390_TLBFLUSH_H */
index 84fefda..fcea067 100644 (file)
@@ -2,7 +2,7 @@
 #define __ASM_SH_DMA_MAPPING_H
 
 #include <linux/mm.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 #include <asm/cacheflush.h>
 #include <asm/io.h>
 
@@ -85,10 +85,9 @@ static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
 
        for (i = 0; i < nents; i++) {
 #if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-               dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
-                              sg[i].length, dir);
+               dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
 #endif
-               sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+               sg[i].dma_address = sg_phys(&sg[i]);
        }
 
        return nents;
@@ -138,10 +137,9 @@ static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
 
        for (i = 0; i < nelems; i++) {
 #if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-               dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
-                              sg[i].length, dir);
+               dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
 #endif
-               sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+               sg[i].dma_address = sg_phys(&sg[i]);
        }
 }
 
index b9ae53c..a7d0d18 100644 (file)
@@ -4,7 +4,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-    struct page * page; /* Location for highmem page, if any */
+#ifdef CONFIG_DEBUG_SG
+    unsigned long sg_magic;
+#endif
+    unsigned long page_link;
     unsigned int offset;/* for highmem, page offset */
     dma_addr_t dma_address;
     unsigned int length;
index e661857..1438b76 100644 (file)
@@ -2,7 +2,7 @@
 #define __ASM_SH_DMA_MAPPING_H
 
 #include <linux/mm.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 #include <asm/io.h>
 
 struct pci_dev;
@@ -71,10 +71,9 @@ static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
 
        for (i = 0; i < nents; i++) {
 #if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-               dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
-                              sg[i].length, dir);
+               dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
 #endif
-               sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+               sg[i].dma_address = sg_phys(&sg[i]);
        }
 
        return nents;
@@ -124,10 +123,9 @@ static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
 
        for (i = 0; i < nelems; i++) {
 #if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-               dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
-                              sg[i].length, dir);
+               dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
 #endif
-               sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+               sg[i].dma_address = sg_phys(&sg[i]);
        }
 }
 
index 1c723f2..5109251 100644 (file)
 #include <asm/types.h>
 
 struct scatterlist {
-    struct page * page; /* Location for highmem page, if any */
+#ifdef CONFIG_DEBUG_SG
+    unsigned long sg_magic;
+#endif
+    unsigned long page_link;
     unsigned int offset;/* for highmem, page offset */
     dma_addr_t dma_address;
     unsigned int length;
index 4055af9..e08d3d7 100644 (file)
@@ -5,7 +5,10 @@
 #include <linux/types.h>
 
 struct scatterlist {
-       struct page *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long sg_magic;
+#endif
+       unsigned long page_link;
        unsigned int offset;
 
        unsigned int length;
index 703c5bb..6df23f0 100644 (file)
@@ -6,7 +6,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-       struct page     *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
        unsigned int    offset;
 
        unsigned int    length;
index 56f4029..02d27b3 100644 (file)
 #include <asm/types.h>
 
 struct scatterlist {
-       struct page     *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
        unsigned        offset;
        dma_addr_t      dma_address;
        unsigned        length;
index 559830e..5e3539c 100644 (file)
@@ -1,6 +1,7 @@
 include include/asm-generic/Kbuild.asm
 
 header-y += boot.h
+header-y += bootparam.h
 header-y += debugreg.h
 header-y += ldt.h
 header-y += msr-index.h
@@ -14,8 +15,10 @@ unifdef-y += a.out_32.h
 unifdef-y += a.out_64.h
 unifdef-y += byteorder_32.h
 unifdef-y += byteorder_64.h
+unifdef-y += e820.h
 unifdef-y += elf_32.h
 unifdef-y += elf_64.h
+unifdef-y += ist.h
 unifdef-y += mce.h
 unifdef-y += msgbuf_32.h
 unifdef-y += msgbuf_64.h
index ef67b59..19f3ddf 100644 (file)
 #include <video/edid.h>
 
 struct setup_header {
-       u8      setup_sects;
-       u16     root_flags;
-       u32     syssize;
-       u16     ram_size;
+       __u8    setup_sects;
+       __u16   root_flags;
+       __u32   syssize;
+       __u16   ram_size;
 #define RAMDISK_IMAGE_START_MASK       0x07FF
 #define RAMDISK_PROMPT_FLAG            0x8000
 #define RAMDISK_LOAD_FLAG              0x4000
-       u16     vid_mode;
-       u16     root_dev;
-       u16     boot_flag;
-       u16     jump;
-       u32     header;
-       u16     version;
-       u32     realmode_swtch;
-       u16     start_sys;
-       u16     kernel_version;
-       u8      type_of_loader;
-       u8      loadflags;
-#define LOADED_HIGH    0x01
-#define CAN_USE_HEAP   0x80
-       u16     setup_move_size;
-       u32     code32_start;
-       u32     ramdisk_image;
-       u32     ramdisk_size;
-       u32     bootsect_kludge;
-       u16     heap_end_ptr;
-       u16     _pad1;
-       u32     cmd_line_ptr;
-       u32     initrd_addr_max;
-       u32     kernel_alignment;
-       u8      relocatable_kernel;
+       __u16   vid_mode;
+       __u16   root_dev;
+       __u16   boot_flag;
+       __u16   jump;
+       __u32   header;
+       __u16   version;
+       __u32   realmode_swtch;
+       __u16   start_sys;
+       __u16   kernel_version;
+       __u8    type_of_loader;
+       __u8    loadflags;
+#define LOADED_HIGH    (1<<0)
+#define KEEP_SEGMENTS  (1<<6)
+#define CAN_USE_HEAP   (1<<7)
+       __u16   setup_move_size;
+       __u32   code32_start;
+       __u32   ramdisk_image;
+       __u32   ramdisk_size;
+       __u32   bootsect_kludge;
+       __u16   heap_end_ptr;
+       __u16   _pad1;
+       __u32   cmd_line_ptr;
+       __u32   initrd_addr_max;
+       __u32   kernel_alignment;
+       __u8    relocatable_kernel;
+       __u8    _pad2[3];
+       __u32   cmdline_size;
+       __u32   hardware_subarch;
+       __u64   hardware_subarch_data;
 } __attribute__((packed));
 
 struct sys_desc_table {
-       u16 length;
-       u8  table[14];
+       __u16 length;
+       __u8  table[14];
 };
 
 struct efi_info {
-       u32 _pad1;
-       u32 efi_systab;
-       u32 efi_memdesc_size;
-       u32 efi_memdesc_version;
-       u32 efi_memmap;
-       u32 efi_memmap_size;
-       u32 _pad2[2];
+       __u32 _pad1;
+       __u32 efi_systab;
+       __u32 efi_memdesc_size;
+       __u32 efi_memdesc_version;
+       __u32 efi_memmap;
+       __u32 efi_memmap_size;
+       __u32 _pad2[2];
 };
 
 /* The so-called "zeropage" */
 struct boot_params {
        struct screen_info screen_info;                 /* 0x000 */
        struct apm_bios_info apm_bios_info;             /* 0x040 */
-       u8  _pad2[12];                                  /* 0x054 */
+       __u8  _pad2[12];                                /* 0x054 */
        struct ist_info ist_info;                       /* 0x060 */
-       u8  _pad3[16];                                  /* 0x070 */
-       u8  hd0_info[16];       /* obsolete! */         /* 0x080 */
-       u8  hd1_info[16];       /* obsolete! */         /* 0x090 */
+       __u8  _pad3[16];                                /* 0x070 */
+       __u8  hd0_info[16];     /* obsolete! */         /* 0x080 */
+       __u8  hd1_info[16];     /* obsolete! */         /* 0x090 */
        struct sys_desc_table sys_desc_table;           /* 0x0a0 */
-       u8  _pad4[144];                                 /* 0x0b0 */
+       __u8  _pad4[144];                               /* 0x0b0 */
        struct edid_info edid_info;                     /* 0x140 */
        struct efi_info efi_info;                       /* 0x1c0 */
-       u32 alt_mem_k;                                  /* 0x1e0 */
-       u32 scratch;            /* Scratch field! */    /* 0x1e4 */
-       u8  e820_entries;                               /* 0x1e8 */
-       u8  eddbuf_entries;                             /* 0x1e9 */
-       u8  edd_mbr_sig_buf_entries;                    /* 0x1ea */
-       u8  _pad6[6];                                   /* 0x1eb */
+       __u32 alt_mem_k;                                /* 0x1e0 */
+       __u32 scratch;          /* Scratch field! */    /* 0x1e4 */
+       __u8  e820_entries;                             /* 0x1e8 */
+       __u8  eddbuf_entries;                           /* 0x1e9 */
+       __u8  edd_mbr_sig_buf_entries;                  /* 0x1ea */
+       __u8  _pad6[6];                                 /* 0x1eb */
        struct setup_header hdr;    /* setup header */  /* 0x1f1 */
-       u8  _pad7[0x290-0x1f1-sizeof(struct setup_header)];
-       u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];        /* 0x290 */
+       __u8  _pad7[0x290-0x1f1-sizeof(struct setup_header)];
+       __u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];      /* 0x290 */
        struct e820entry e820_map[E820MAX];             /* 0x2d0 */
-       u8  _pad8[48];                                  /* 0xcd0 */
+       __u8  _pad8[48];                                /* 0xcd0 */
        struct edd_info eddbuf[EDDMAXNR];               /* 0xd00 */
-       u8  _pad9[276];                                 /* 0xeec */
+       __u8  _pad9[276];                               /* 0xeec */
 } __attribute__((packed));
 
 #endif /* _ASM_BOOTPARAM_H */
index b3d43de..9411a2d 100644 (file)
@@ -27,6 +27,7 @@
 void global_flush_tlb(void);
 int change_page_attr(struct page *page, int numpages, pgprot_t prot);
 int change_page_attr_addr(unsigned long addr, int numpages, pgprot_t prot);
+void clflush_cache_range(void *addr, int size);
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 /* internal debugging function */
index d9ee5e5..87a7153 100644 (file)
@@ -5,6 +5,9 @@ struct dev_archdata {
 #ifdef CONFIG_ACPI
        void    *acpi_handle;
 #endif
+#ifdef CONFIG_DMAR
+       void *iommu; /* hook for IOMMU specific extension */
+#endif
 };
 
 #endif /* _ASM_X86_DEVICE_H */
index 6a2d26c..55f01bd 100644 (file)
@@ -45,9 +45,9 @@ dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
        WARN_ON(nents == 0 || sglist[0].length == 0);
 
        for_each_sg(sglist, sg, nents, i) {
-               BUG_ON(!sg->page);
+               BUG_ON(!sg_page(sg));
 
-               sg->dma_address = page_to_phys(sg->page) + sg->offset;
+               sg->dma_address = sg_phys(sg);
        }
 
        flush_write_buffers();
index 5d4d218..3e214f3 100644 (file)
@@ -1,5 +1,33 @@
+#ifndef __ASM_E820_H
+#define __ASM_E820_H
+#define E820MAP        0x2d0           /* our map */
+#define E820MAX        128             /* number of entries in E820MAP */
+#define E820NR 0x1e8           /* # entries in E820MAP */
+
+#define E820_RAM       1
+#define E820_RESERVED  2
+#define E820_ACPI      3
+#define E820_NVS       4
+
+#ifndef __ASSEMBLY__
+struct e820entry {
+       __u64 addr;     /* start of memory segment */
+       __u64 size;     /* size of memory segment */
+       __u32 type;     /* type of memory segment */
+} __attribute__((packed));
+
+struct e820map {
+       __u32 nr_map;
+       struct e820entry map[E820MAX];
+};
+#endif /* __ASSEMBLY__ */
+
+#ifdef __KERNEL__
 #ifdef CONFIG_X86_32
 # include "e820_32.h"
 #else
 # include "e820_64.h"
 #endif
+#endif /* __KERNEL__ */
+
+#endif  /* __ASM_E820_H */
index cf67dbb..03f60c6 100644 (file)
 #ifndef __E820_HEADER
 #define __E820_HEADER
 
-#define E820MAP        0x2d0           /* our map */
-#define E820MAX        128             /* number of entries in E820MAP */
-#define E820NR 0x1e8           /* # entries in E820MAP */
-
-#define E820_RAM       1
-#define E820_RESERVED  2
-#define E820_ACPI      3
-#define E820_NVS       4
-
 #define HIGH_MEMORY    (1024*1024)
 
 #ifndef __ASSEMBLY__
 
-struct e820entry {
-       u64 addr;       /* start of memory segment */
-       u64 size;       /* size of memory segment */
-       u32 type;       /* type of memory segment */
-} __attribute__((packed));
-
-struct e820map {
-       u32 nr_map;
-       struct e820entry map[E820MAX];
-};
-
 extern struct e820map e820;
 
 extern int e820_all_mapped(unsigned long start, unsigned long end,
@@ -56,5 +36,4 @@ static inline void e820_mark_nosave_regions(void)
 #endif
 
 #endif/*!__ASSEMBLY__*/
-
 #endif/*__E820_HEADER*/
index 3486e70..0bd4787 100644 (file)
 #ifndef __E820_HEADER
 #define __E820_HEADER
 
-#define E820MAP        0x2d0           /* our map */
-#define E820MAX        128             /* number of entries in E820MAP */
-#define E820NR 0x1e8           /* # entries in E820MAP */
-
-#define E820_RAM       1
-#define E820_RESERVED  2
-#define E820_ACPI      3
-#define E820_NVS       4
-
 #ifndef __ASSEMBLY__
-struct e820entry {
-       u64 addr;       /* start of memory segment */
-       u64 size;       /* size of memory segment */
-       u32 type;       /* type of memory segment */
-} __attribute__((packed));
-
-struct e820map {
-       u32 nr_map;
-       struct e820entry map[E820MAX];
-};
-
 extern unsigned long find_e820_area(unsigned long start, unsigned long end, 
                                    unsigned size);
 extern void add_memory_region(unsigned long start, unsigned long size, 
index ef2003e..6ec6cee 100644 (file)
  */
 
 
-#ifdef __KERNEL__
-
 #include <linux/types.h>
 
 struct ist_info {
-       u32 signature;
-       u32 command;
-       u32 event;
-       u32 perf_level;
+       __u32 signature;
+       __u32 command;
+       __u32 event;
+       __u32 perf_level;
 };
 
+#ifdef __KERNEL__
+
 extern struct ist_info ist_info;
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-x86/lguest.h b/include/asm-x86/lguest.h
new file mode 100644 (file)
index 0000000..ccd3384
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef _X86_LGUEST_H
+#define _X86_LGUEST_H
+
+#define GDT_ENTRY_LGUEST_CS    10
+#define GDT_ENTRY_LGUEST_DS    11
+#define LGUEST_CS              (GDT_ENTRY_LGUEST_CS * 8)
+#define LGUEST_DS              (GDT_ENTRY_LGUEST_DS * 8)
+
+#ifndef __ASSEMBLY__
+#include <asm/desc.h>
+
+#define GUEST_PL 1
+
+/* Every guest maps the core switcher code. */
+#define SHARED_SWITCHER_PAGES \
+       DIV_ROUND_UP(end_switcher_text - start_switcher_text, PAGE_SIZE)
+/* Pages for switcher itself, then two pages per cpu */
+#define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * NR_CPUS)
+
+/* We map at -4M for ease of mapping into the guest (one PTE page). */
+#define SWITCHER_ADDR 0xFFC00000
+
+/* Found in switcher.S */
+extern unsigned long default_idt_entries[];
+
+struct lguest_regs
+{
+       /* Manually saved part. */
+       unsigned long eax, ebx, ecx, edx;
+       unsigned long esi, edi, ebp;
+       unsigned long gs;
+       unsigned long fs, ds, es;
+       unsigned long trapnum, errcode;
+       /* Trap pushed part */
+       unsigned long eip;
+       unsigned long cs;
+       unsigned long eflags;
+       unsigned long esp;
+       unsigned long ss;
+};
+
+/* This is a guest-specific page (mapped ro) into the guest. */
+struct lguest_ro_state
+{
+       /* Host information we need to restore when we switch back. */
+       u32 host_cr3;
+       struct Xgt_desc_struct host_idt_desc;
+       struct Xgt_desc_struct host_gdt_desc;
+       u32 host_sp;
+
+       /* Fields which are used when guest is running. */
+       struct Xgt_desc_struct guest_idt_desc;
+       struct Xgt_desc_struct guest_gdt_desc;
+       struct i386_hw_tss guest_tss;
+       struct desc_struct guest_idt[IDT_ENTRIES];
+       struct desc_struct guest_gdt[GDT_ENTRIES];
+};
+
+struct lguest_arch
+{
+       /* The GDT entries copied into lguest_ro_state when running. */
+       struct desc_struct gdt[GDT_ENTRIES];
+
+       /* The IDT entries: some copied into lguest_ro_state when running. */
+       struct desc_struct idt[IDT_ENTRIES];
+
+       /* The address of the last guest-visible pagefault (ie. cr2). */
+       unsigned long last_pagefault;
+};
+
+static inline void lguest_set_ts(void)
+{
+       u32 cr0;
+
+       cr0 = read_cr0();
+       if (!(cr0 & 8))
+               write_cr0(cr0|8);
+}
+
+/* Full 4G segment descriptors, suitable for CS and DS. */
+#define FULL_EXEC_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9b00})
+#define FULL_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9300})
+
+#endif /* __ASSEMBLY__ */
+
+#endif
diff --git a/include/asm-x86/lguest_hcall.h b/include/asm-x86/lguest_hcall.h
new file mode 100644 (file)
index 0000000..f948491
--- /dev/null
@@ -0,0 +1,71 @@
+/* Architecture specific portion of the lguest hypercalls */
+#ifndef _X86_LGUEST_HCALL_H
+#define _X86_LGUEST_HCALL_H
+
+#define LHCALL_FLUSH_ASYNC     0
+#define LHCALL_LGUEST_INIT     1
+#define LHCALL_CRASH           2
+#define LHCALL_LOAD_GDT                3
+#define LHCALL_NEW_PGTABLE     4
+#define LHCALL_FLUSH_TLB       5
+#define LHCALL_LOAD_IDT_ENTRY  6
+#define LHCALL_SET_STACK       7
+#define LHCALL_TS              8
+#define LHCALL_SET_CLOCKEVENT  9
+#define LHCALL_HALT            10
+#define LHCALL_SET_PTE         14
+#define LHCALL_SET_PMD         15
+#define LHCALL_LOAD_TLS                16
+#define LHCALL_NOTIFY          17
+
+/*G:031 First, how does our Guest contact the Host to ask for privileged
+ * operations?  There are two ways: the direct way is to make a "hypercall",
+ * to make requests of the Host Itself.
+ *
+ * Our hypercall mechanism uses the highest unused trap code (traps 32 and
+ * above are used by real hardware interrupts).  Seventeen hypercalls are
+ * available: the hypercall number is put in the %eax register, and the
+ * arguments (when required) are placed in %edx, %ebx and %ecx.  If a return
+ * value makes sense, it's returned in %eax.
+ *
+ * Grossly invalid calls result in Sudden Death at the hands of the vengeful
+ * Host, rather than returning failure.  This reflects Winston Churchill's
+ * definition of a gentleman: "someone who is only rude intentionally". */
+#define LGUEST_TRAP_ENTRY 0x1F
+
+#ifndef __ASSEMBLY__
+#include <asm/hw_irq.h>
+
+static inline unsigned long
+hcall(unsigned long call,
+      unsigned long arg1, unsigned long arg2, unsigned long arg3)
+{
+       /* "int" is the Intel instruction to trigger a trap. */
+       asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY)
+                      /* The call is in %eax (aka "a"), and can be replaced */
+                    : "=a"(call)
+                      /* The other arguments are in %eax, %edx, %ebx & %ecx */
+                    : "a"(call), "d"(arg1), "b"(arg2), "c"(arg3)
+                      /* "memory" means this might write somewhere in memory.
+                       * This isn't true for all calls, but it's safe to tell
+                       * gcc that it might happen so it doesn't get clever. */
+                    : "memory");
+       return call;
+}
+/*:*/
+
+void async_hcall(unsigned long call,
+                unsigned long arg1, unsigned long arg2, unsigned long arg3);
+
+/* Can't use our min() macro here: needs to be a constant */
+#define LGUEST_IRQS (NR_IRQS < 32 ? NR_IRQS: 32)
+
+#define LHCALL_RING_SIZE 64
+struct hcall_args
+{
+       /* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */
+       unsigned long arg0, arg2, arg3, arg1;
+};
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _I386_LGUEST_HCALL_H */
index bd5164a..0e7d997 100644 (file)
@@ -4,7 +4,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-    struct page                *page;
+#ifdef CONFIG_DEBUG_SG
+    unsigned long      sg_magic;
+#endif
+    unsigned long      page_link;
     unsigned int       offset;
     dma_addr_t         dma_address;
     unsigned int       length;
index ef3986b..1847c72 100644 (file)
@@ -4,7 +4,10 @@
 #include <asm/types.h>
 
 struct scatterlist {
-    struct page                *page;
+#ifdef CONFIG_DEBUG_SG
+    unsigned long      sg_magic;
+#endif
+    unsigned long      page_link;
     unsigned int       offset;
     unsigned int       length;
     dma_addr_t         dma_address;
index 82b03b3..8bd9d2c 100644 (file)
@@ -58,11 +58,10 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
        BUG_ON(direction == DMA_NONE);
 
        for (i = 0; i < nents; i++, sg++ ) {
-               BUG_ON(!sg->page);
+               BUG_ON(!sg_page(sg));
 
-               sg->dma_address = page_to_phys(sg->page) + sg->offset;
-               consistent_sync(page_address(sg->page) + sg->offset,
-                               sg->length, direction);
+               sg->dma_address = sg_phys(sg);
+               consistent_sync(sg_virt(sg), sg->length, direction);
        }
 
        return nents;
@@ -128,8 +127,7 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
 {
        int i;
        for (i = 0; i < nelems; i++, sg++)
-               consistent_sync(page_address(sg->page) + sg->offset,
-                               sg->length, dir);
+               consistent_sync(sg_virt(sg), sg->length, dir);
 }
 
 static inline void
@@ -138,8 +136,7 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
 {
        int i;
        for (i = 0; i < nelems; i++, sg++)
-               consistent_sync(page_address(sg->page) + sg->offset,
-                               sg->length, dir);
+               consistent_sync(sg_virt(sg), sg->length, dir);
 }
 static inline int
 dma_mapping_error(dma_addr_t dma_addr)
index ca337a2..810080b 100644 (file)
 #include <asm/types.h>
 
 struct scatterlist {
-       struct page     *page;
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
        unsigned int    offset;
        dma_addr_t      dma_address;
        unsigned int    length;
index e3ffd14..6a65231 100644 (file)
@@ -186,6 +186,7 @@ unifdef-y += cyclades.h
 unifdef-y += dccp.h
 unifdef-y += dirent.h
 unifdef-y += dlm.h
+unifdef-y += edd.h
 unifdef-y += elfcore.h
 unifdef-y += errno.h
 unifdef-y += errqueue.h
@@ -306,6 +307,7 @@ unifdef-y += rtc.h
 unifdef-y += rtnetlink.h
 unifdef-y += scc.h
 unifdef-y += sched.h
+unifdef-y += screen_info.h
 unifdef-y += sdla.h
 unifdef-y += selinux_netlink.h
 unifdef-y += sem.h
@@ -341,6 +343,9 @@ unifdef-y += user.h
 unifdef-y += utsname.h
 unifdef-y += videodev2.h
 unifdef-y += videodev.h
+unifdef-y += virtio_config.h
+unifdef-y += virtio_blk.h
+unifdef-y += virtio_net.h
 unifdef-y += wait.h
 unifdef-y += wanrouter.h
 unifdef-y += watchdog.h
index 5f921c8..9754baa 100644 (file)
  * General Public License for more details.
  */
 
-typedef unsigned short apm_event_t;
-typedef unsigned short apm_eventinfo_t;
+#include <linux/types.h>
+
+struct apm_bios_info {
+       __u16   version;
+       __u16   cseg;
+       __u32   offset;
+       __u16   cseg_16;
+       __u16   dseg;
+       __u16   flags;
+       __u16   cseg_len;
+       __u16   cseg_16_len;
+       __u16   dseg_len;
+};
 
 #ifdef __KERNEL__
 
-#include <linux/types.h>
+typedef unsigned short apm_event_t;
+typedef unsigned short apm_eventinfo_t;
 
 #define APM_CS         (GDT_ENTRY_APMBIOS_BASE * 8)
 #define APM_CS_16      (APM_CS + 8)
 #define APM_DS         (APM_CS_16 + 8)
 
-struct apm_bios_info {
-       u16     version;
-       u16     cseg;
-       u32     offset;
-       u16     cseg_16;
-       u16     dseg;
-       u16     flags;
-       u16     cseg_len;
-       u16     cseg_16_len;
-       u16     dseg_len;
-};
-
 /* Results of APM Installation Check */
 #define APM_16_BIT_SUPPORT     0x0001
 #define APM_32_BIT_SUPPORT     0x0002
index 9ae7409..c687816 100644 (file)
@@ -63,6 +63,8 @@
 #define AUDIT_ADD_RULE         1011    /* Add syscall filtering rule */
 #define AUDIT_DEL_RULE         1012    /* Delete syscall filtering rule */
 #define AUDIT_LIST_RULES       1013    /* List syscall filtering rules */
+#define AUDIT_TRIM             1014    /* Trim junk from watched tree */
+#define AUDIT_MAKE_EQUIV       1015    /* Append to watched tree */
 #define AUDIT_TTY_GET          1016    /* Get TTY auditing status */
 #define AUDIT_TTY_SET          1017    /* Set TTY auditing status */
 
 #define AUDIT_SUCCESS   104    /* exit >= 0; value ignored */
 #define AUDIT_WATCH    105
 #define AUDIT_PERM     106
+#define AUDIT_DIR      107
 
 #define AUDIT_ARG0      200
 #define AUDIT_ARG1      (AUDIT_ARG0+1)
@@ -366,8 +369,8 @@ extern void audit_syscall_entry(int arch,
 extern void audit_syscall_exit(int failed, long return_code);
 extern void __audit_getname(const char *name);
 extern void audit_putname(const char *name);
-extern void __audit_inode(const char *name, const struct inode *inode);
-extern void __audit_inode_child(const char *dname, const struct inode *inode,
+extern void __audit_inode(const char *name, const struct dentry *dentry);
+extern void __audit_inode_child(const char *dname, const struct dentry *dentry,
                                const struct inode *parent);
 extern void __audit_ptrace(struct task_struct *t);
 
@@ -381,15 +384,15 @@ static inline void audit_getname(const char *name)
        if (unlikely(!audit_dummy_context()))
                __audit_getname(name);
 }
-static inline void audit_inode(const char *name, const struct inode *inode) {
+static inline void audit_inode(const char *name, const struct dentry *dentry) {
        if (unlikely(!audit_dummy_context()))
-               __audit_inode(name, inode);
+               __audit_inode(name, dentry);
 }
 static inline void audit_inode_child(const char *dname, 
-                                    const struct inode *inode,
+                                    const struct dentry *dentry,
                                     const struct inode *parent) {
        if (unlikely(!audit_dummy_context()))
-               __audit_inode_child(dname, inode, parent);
+               __audit_inode_child(dname, dentry, parent);
 }
 void audit_core_dumps(long signr);
 
@@ -477,9 +480,9 @@ extern int audit_signals;
 #define audit_dummy_context() 1
 #define audit_getname(n) do { ; } while (0)
 #define audit_putname(n) do { ; } while (0)
-#define __audit_inode(n,i) do { ; } while (0)
+#define __audit_inode(n,d) do { ; } while (0)
 #define __audit_inode_child(d,i,p) do { ; } while (0)
-#define audit_inode(n,i) do { ; } while (0)
+#define audit_inode(n,d) do { ; } while (0)
 #define audit_inode_child(d,i,p) do { ; } while (0)
 #define audit_core_dumps(i) do { ; } while (0)
 #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
index 7a8d7ad..bb017ed 100644 (file)
@@ -56,10 +56,8 @@ typedef struct __user_cap_data_struct {
 
 struct vfs_cap_data {
        __u32 magic_etc;  /* Little endian */
-       struct {
-               __u32 permitted;    /* Little endian */
-               __u32 inheritable;  /* Little endian */
-       } data[1];
+       __u32 permitted;    /* Little endian */
+       __u32 inheritable;  /* Little endian */
 };
 
 #ifdef __KERNEL__
index aab53df..c2c153f 100644 (file)
@@ -178,6 +178,7 @@ d_iput:             no              no              no       yes
 #define DCACHE_INOTIFY_PARENT_WATCHED  0x0020 /* Parent inode is watched */
 
 extern spinlock_t dcache_lock;
+extern seqlock_t rename_lock;
 
 /**
  * d_drop - drop a dentry
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
new file mode 100644 (file)
index 0000000..ffb6439
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Ashok Raj <ashok.raj@intel.com>
+ * Copyright (C) Shaohua Li <shaohua.li@intel.com>
+ */
+
+#ifndef __DMAR_H__
+#define __DMAR_H__
+
+#include <linux/acpi.h>
+#include <linux/types.h>
+#include <linux/msi.h>
+
+#ifdef CONFIG_DMAR
+struct intel_iommu;
+
+extern char *dmar_get_fault_reason(u8 fault_reason);
+
+/* Can't use the common MSI interrupt functions
+ * since DMAR is not a pci device
+ */
+extern void dmar_msi_unmask(unsigned int irq);
+extern void dmar_msi_mask(unsigned int irq);
+extern void dmar_msi_read(int irq, struct msi_msg *msg);
+extern void dmar_msi_write(int irq, struct msi_msg *msg);
+extern int dmar_set_interrupt(struct intel_iommu *iommu);
+extern int arch_setup_dmar_msi(unsigned int irq);
+
+/* Intel IOMMU detection and initialization functions */
+extern void detect_intel_iommu(void);
+extern int intel_iommu_init(void);
+
+extern int dmar_table_init(void);
+extern int early_dmar_detect(void);
+
+extern struct list_head dmar_drhd_units;
+extern struct list_head dmar_rmrr_units;
+
+struct dmar_drhd_unit {
+       struct list_head list;          /* list of drhd units   */
+       u64     reg_base_addr;          /* register base address*/
+       struct  pci_dev **devices;      /* target device array  */
+       int     devices_cnt;            /* target device count  */
+       u8      ignored:1;              /* ignore drhd          */
+       u8      include_all:1;
+       struct intel_iommu *iommu;
+};
+
+struct dmar_rmrr_unit {
+       struct list_head list;          /* list of rmrr units   */
+       u64     base_address;           /* reserved base address*/
+       u64     end_address;            /* reserved end address */
+       struct pci_dev **devices;       /* target devices */
+       int     devices_cnt;            /* target device count */
+};
+
+#define for_each_drhd_unit(drhd) \
+       list_for_each_entry(drhd, &dmar_drhd_units, list)
+#define for_each_rmrr_units(rmrr) \
+       list_for_each_entry(rmrr, &dmar_rmrr_units, list)
+#else
+static inline void detect_intel_iommu(void)
+{
+       return;
+}
+static inline int intel_iommu_init(void)
+{
+       return -ENODEV;
+}
+
+#endif /* !CONFIG_DMAR */
+#endif /* __DMAR_H__ */
index 7b64782..5d747c5 100644 (file)
 #define EDD_INFO_USE_INT13_FN50                (1 << 7)
 
 struct edd_device_params {
-       u16 length;
-       u16 info_flags;
-       u32 num_default_cylinders;
-       u32 num_default_heads;
-       u32 sectors_per_track;
-       u64 number_of_sectors;
-       u16 bytes_per_sector;
-       u32 dpte_ptr;           /* 0xFFFFFFFF for our purposes */
-       u16 key;                /* = 0xBEDD */
-       u8 device_path_info_length;     /* = 44 */
-       u8 reserved2;
-       u16 reserved3;
-       u8 host_bus_type[4];
-       u8 interface_type[8];
+       __u16 length;
+       __u16 info_flags;
+       __u32 num_default_cylinders;
+       __u32 num_default_heads;
+       __u32 sectors_per_track;
+       __u64 number_of_sectors;
+       __u16 bytes_per_sector;
+       __u32 dpte_ptr;         /* 0xFFFFFFFF for our purposes */
+       __u16 key;              /* = 0xBEDD */
+       __u8 device_path_info_length;   /* = 44 */
+       __u8 reserved2;
+       __u16 reserved3;
+       __u8 host_bus_type[4];
+       __u8 interface_type[8];
        union {
                struct {
-                       u16 base_address;
-                       u16 reserved1;
-                       u32 reserved2;
+                       __u16 base_address;
+                       __u16 reserved1;
+                       __u32 reserved2;
                } __attribute__ ((packed)) isa;
                struct {
-                       u8 bus;
-                       u8 slot;
-                       u8 function;
-                       u8 channel;
-                       u32 reserved;
+                       __u8 bus;
+                       __u8 slot;
+                       __u8 function;
+                       __u8 channel;
+                       __u32 reserved;
                } __attribute__ ((packed)) pci;
                /* pcix is same as pci */
                struct {
-                       u64 reserved;
+                       __u64 reserved;
                } __attribute__ ((packed)) ibnd;
                struct {
-                       u64 reserved;
+                       __u64 reserved;
                } __attribute__ ((packed)) xprs;
                struct {
-                       u64 reserved;
+                       __u64 reserved;
                } __attribute__ ((packed)) htpt;
                struct {
-                       u64 reserved;
+                       __u64 reserved;
                } __attribute__ ((packed)) unknown;
        } interface_path;
        union {
                struct {
-                       u8 device;
-                       u8 reserved1;
-                       u16 reserved2;
-                       u32 reserved3;
-                       u64 reserved4;
+                       __u8 device;
+                       __u8 reserved1;
+                       __u16 reserved2;
+                       __u32 reserved3;
+                       __u64 reserved4;
                } __attribute__ ((packed)) ata;
                struct {
-                       u8 device;
-                       u8 lun;
-                       u8 reserved1;
-                       u8 reserved2;
-                       u32 reserved3;
-                       u64 reserved4;
+                       __u8 device;
+                       __u8 lun;
+                       __u8 reserved1;
+                       __u8 reserved2;
+                       __u32 reserved3;
+                       __u64 reserved4;
                } __attribute__ ((packed)) atapi;
                struct {
-                       u16 id;
-                       u64 lun;
-                       u16 reserved1;
-                       u32 reserved2;
+                       __u16 id;
+                       __u64 lun;
+                       __u16 reserved1;
+                       __u32 reserved2;
                } __attribute__ ((packed)) scsi;
                struct {
-                       u64 serial_number;
-                       u64 reserved;
+                       __u64 serial_number;
+                       __u64 reserved;
                } __attribute__ ((packed)) usb;
                struct {
-                       u64 eui;
-                       u64 reserved;
+                       __u64 eui;
+                       __u64 reserved;
                } __attribute__ ((packed)) i1394;
                struct {
-                       u64 wwid;
-                       u64 lun;
+                       __u64 wwid;
+                       __u64 lun;
                } __attribute__ ((packed)) fibre;
                struct {
-                       u64 identity_tag;
-                       u64 reserved;
+                       __u64 identity_tag;
+                       __u64 reserved;
                } __attribute__ ((packed)) i2o;
                struct {
-                       u32 array_number;
-                       u32 reserved1;
-                       u64 reserved2;
+                       __u32 array_number;
+                       __u32 reserved1;
+                       __u64 reserved2;
                } __attribute__ ((packed)) raid;
                struct {
-                       u8 device;
-                       u8 reserved1;
-                       u16 reserved2;
-                       u32 reserved3;
-                       u64 reserved4;
+                       __u8 device;
+                       __u8 reserved1;
+                       __u16 reserved2;
+                       __u32 reserved3;
+                       __u64 reserved4;
                } __attribute__ ((packed)) sata;
                struct {
-                       u64 reserved1;
-                       u64 reserved2;
+                       __u64 reserved1;
+                       __u64 reserved2;
                } __attribute__ ((packed)) unknown;
        } device_path;
-       u8 reserved4;
-       u8 checksum;
+       __u8 reserved4;
+       __u8 checksum;
 } __attribute__ ((packed));
 
 struct edd_info {
-       u8 device;
-       u8 version;
-       u16 interface_support;
-       u16 legacy_max_cylinder;
-       u8 legacy_max_head;
-       u8 legacy_sectors_per_track;
+       __u8 device;
+       __u8 version;
+       __u16 interface_support;
+       __u16 legacy_max_cylinder;
+       __u8 legacy_max_head;
+       __u8 legacy_sectors_per_track;
        struct edd_device_params params;
 } __attribute__ ((packed));
 
@@ -184,8 +184,9 @@ struct edd {
        unsigned char edd_info_nr;
 };
 
+#ifdef __KERNEL__
 extern struct edd edd;
-
+#endif /* __KERNEL__ */
 #endif                         /*!__ASSEMBLY__ */
 
 #endif                         /* _LINUX_EDD_H */
index 0b9579a..14813b5 100644 (file)
@@ -298,7 +298,7 @@ extern int efi_mem_attribute_range (unsigned long phys_addr, unsigned long size,
                                    u64 attr);
 extern int __init efi_uart_console_only (void);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
-                                       struct resource *data_resource);
+               struct resource *data_resource, struct resource *bss_resource);
 extern unsigned long efi_get_time(void);
 extern int efi_set_rtc_mmss(unsigned long nowtime);
 extern int is_available_memory(efi_memory_desc_t * md);
index 16cb25c..dd57fe5 100644 (file)
@@ -35,6 +35,7 @@ static inline struct efs_sb_info *SUPER_INFO(struct super_block *sb)
 }
 
 struct statfs;
+struct fid;
 
 extern const struct inode_operations efs_dir_inode_operations;
 extern const struct file_operations efs_dir_operations;
@@ -45,7 +46,10 @@ extern efs_block_t efs_map_block(struct inode *, efs_block_t);
 extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *);
-extern struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp);
+extern struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type);
+extern struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type);
 extern struct dentry *efs_get_parent(struct dentry *);
 extern int efs_bmap(struct inode *, int);
 
index 8872fe8..51d2141 100644 (file)
@@ -4,9 +4,48 @@
 #include <linux/types.h>
 
 struct dentry;
+struct inode;
 struct super_block;
 struct vfsmount;
 
+/*
+ * The fileid_type identifies how the file within the filesystem is encoded.
+ * In theory this is freely set and parsed by the filesystem, but we try to
+ * stick to conventions so we can share some generic code and don't confuse
+ * sniffers like ethereal/wireshark.
+ *
+ * The filesystem must not use the value '0' or '0xff'.
+ */
+enum fid_type {
+       /*
+        * The root, or export point, of the filesystem.
+        * (Never actually passed down to the filesystem.
+        */
+       FILEID_ROOT = 0,
+
+       /*
+        * 32bit inode number, 32 bit generation number.
+        */
+       FILEID_INO32_GEN = 1,
+
+       /*
+        * 32bit inode number, 32 bit generation number,
+        * 32 bit parent directory inode number.
+        */
+       FILEID_INO32_GEN_PARENT = 2,
+};
+
+struct fid {
+       union {
+               struct {
+                       u32 ino;
+                       u32 gen;
+                       u32 parent_ino;
+                       u32 parent_gen;
+               } i32;
+               __u32 raw[6];
+       };
+};
 
 /**
  * struct export_operations - for nfsd to communicate with file systems
@@ -15,43 +54,9 @@ struct vfsmount;
  * @get_name:       find the name for a given inode in a given directory
  * @get_parent:     find the parent of a given directory
  * @get_dentry:     find a dentry for the inode given a file handle sub-fragment
- * @find_exported_dentry:
- *     set by the exporting module to a standard helper function.
- *
- * Description:
- *    The export_operations structure provides a means for nfsd to communicate
- *    with a particular exported file system  - particularly enabling nfsd and
- *    the filesystem to co-operate when dealing with file handles.
- *
- *    export_operations contains two basic operation for dealing with file
- *    handles, decode_fh() and encode_fh(), and allows for some other
- *    operations to be defined which standard helper routines use to get
- *    specific information from the filesystem.
- *
- *    nfsd encodes information use to determine which filesystem a filehandle
- *    applies to in the initial part of the file handle.  The remainder, termed
- *    a file handle fragment, is controlled completely by the filesystem.  The
- *    standard helper routines assume that this fragment will contain one or
- *    two sub-fragments, one which identifies the file, and one which may be
- *    used to identify the (a) directory containing the file.
  *
- *    In some situations, nfsd needs to get a dentry which is connected into a
- *    specific part of the file tree.  To allow for this, it passes the
- *    function acceptable() together with a @context which can be used to see
- *    if the dentry is acceptable.  As there can be multiple dentrys for a
- *    given file, the filesystem should check each one for acceptability before
- *    looking for the next.  As soon as an acceptable one is found, it should
- *    be returned.
- *
- * decode_fh:
- *    @decode_fh is given a &struct super_block (@sb), a file handle fragment
- *    (@fh, @fh_len) and an acceptability testing function (@acceptable,
- *    @context).  It should return a &struct dentry which refers to the same
- *    file that the file handle fragment refers to,  and which passes the
- *    acceptability test.  If it cannot, it should return a %NULL pointer if
- *    the file was found but no acceptable &dentries were available, or a
- *    %ERR_PTR error code indicating why it couldn't be found (e.g. %ENOENT or
- *    %ENOMEM).
+ * See Documentation/filesystems/Exporting for details on how to use
+ * this interface correctly.
  *
  * encode_fh:
  *    @encode_fh should store in the file handle fragment @fh (using at most
@@ -63,6 +68,21 @@ struct vfsmount;
  *    the filehandle fragment.  encode_fh() should return the number of bytes
  *    stored or a negative error code such as %-ENOSPC
  *
+ * fh_to_dentry:
+ *    @fh_to_dentry is given a &struct super_block (@sb) and a file handle
+ *    fragment (@fh, @fh_len). It should return a &struct dentry which refers
+ *    to the same file that the file handle fragment refers to.  If it cannot,
+ *    it should return a %NULL pointer if the file was found but no acceptable
+ *    &dentries were available, or an %ERR_PTR error code indicating why it
+ *    couldn't be found (e.g. %ENOENT or %ENOMEM).  Any suitable dentry can be
+ *    returned including, if necessary, a new dentry created with d_alloc_root.
+ *    The caller can then find any other extant dentries by following the
+ *    d_alias links.
+ *
+ * fh_to_parent:
+ *    Same as @fh_to_dentry, except that it returns a pointer to the parent
+ *    dentry if it was encoded into the filehandle fragment by @encode_fh.
+ *
  * get_name:
  *    @get_name should find a name for the given @child in the given @parent
  *    directory.  The name should be stored in the @name (with the
@@ -75,52 +95,37 @@ struct vfsmount;
  *    is also a directory.  In the event that it cannot be found, or storage
  *    space cannot be allocated, a %ERR_PTR should be returned.
  *
- * get_dentry:
- *    Given a &super_block (@sb) and a pointer to a file-system specific inode
- *    identifier, possibly an inode number, (@inump) get_dentry() should find
- *    the identified inode and return a dentry for that inode.  Any suitable
- *    dentry can be returned including, if necessary, a new dentry created with
- *    d_alloc_root.  The caller can then find any other extant dentrys by
- *    following the d_alias links.  If a new dentry was created using
- *    d_alloc_root, DCACHE_NFSD_DISCONNECTED should be set, and the dentry
- *    should be d_rehash()ed.
- *
- *    If the inode cannot be found, either a %NULL pointer or an %ERR_PTR code
- *    can be returned.  The @inump will be whatever was passed to
- *    nfsd_find_fh_dentry() in either the @obj or @parent parameters.
- *
  * Locking rules:
  *    get_parent is called with child->d_inode->i_mutex down
  *    get_name is not (which is possibly inconsistent)
  */
 
 struct export_operations {
-       struct dentry *(*decode_fh)(struct super_block *sb, __u32 *fh,
-                       int fh_len, int fh_type,
-                       int (*acceptable)(void *context, struct dentry *de),
-                       void *context);
        int (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len,
                        int connectable);
+       struct dentry * (*fh_to_dentry)(struct super_block *sb, struct fid *fid,
+                       int fh_len, int fh_type);
+       struct dentry * (*fh_to_parent)(struct super_block *sb, struct fid *fid,
+                       int fh_len, int fh_type);
        int (*get_name)(struct dentry *parent, char *name,
                        struct dentry *child);
        struct dentry * (*get_parent)(struct dentry *child);
-       struct dentry * (*get_dentry)(struct super_block *sb, void *inump);
-
-       /* This is set by the exporting module to a standard helper */
-       struct dentry * (*find_exported_dentry)(
-                       struct super_block *sb, void *obj, void *parent,
-                       int (*acceptable)(void *context, struct dentry *de),
-                       void *context);
 };
 
-extern struct dentry *find_exported_dentry(struct super_block *sb, void *obj,
-       void *parent, int (*acceptable)(void *context, struct dentry *de),
-       void *context);
-
-extern int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
-       int connectable);
-extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh,
+extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
+       int *max_len, int connectable);
+extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
        int fh_len, int fileid_type, int (*acceptable)(void *, struct dentry *),
        void *context);
 
+/*
+ * Generic helpers for filesystems.
+ */
+extern struct dentry *generic_fh_to_dentry(struct super_block *sb,
+       struct fid *fid, int fh_len, int fh_type,
+       struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen));
+extern struct dentry *generic_fh_to_parent(struct super_block *sb,
+       struct fid *fid, int fh_len, int fh_type,
+       struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen));
+
 #endif /* LINUX_EXPORTFS_H */
index c77c3bb..0f6c86c 100644 (file)
@@ -561,6 +561,7 @@ enum {
 #define EXT2_DIR_ROUND                         (EXT2_DIR_PAD - 1)
 #define EXT2_DIR_REC_LEN(name_len)     (((name_len) + 8 + EXT2_DIR_ROUND) & \
                                         ~EXT2_DIR_ROUND)
+#define EXT2_MAX_REC_LEN               ((1<<16)-1)
 
 static inline ext2_fsblk_t
 ext2_group_first_block_no(struct super_block *sb, unsigned long group_no)
index 1bcce66..b3ec4a4 100644 (file)
@@ -987,7 +987,7 @@ struct super_block {
        const struct super_operations   *s_op;
        struct dquot_operations *dq_op;
        struct quotactl_ops     *s_qcop;
-       struct export_operations *s_export_op;
+       const struct export_operations *s_export_op;
        unsigned long           s_flags;
        unsigned long           s_magic;
        struct dentry           *s_root;
@@ -1470,6 +1470,8 @@ extern long do_mount(char *, char *, char *, unsigned long, void *);
 extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
 extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
                                  struct vfsmount *);
+extern struct vfsmount *collect_mounts(struct vfsmount *, struct dentry *);
+extern void drop_collected_mounts(struct vfsmount *);
 
 extern int vfs_statfs(struct dentry *, struct kstatfs *);
 
index dfc4e4f..2bd31fa 100644 (file)
@@ -41,8 +41,9 @@ static inline void fsnotify_d_move(struct dentry *entry)
  */
 static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
                                 const char *old_name, const char *new_name,
-                                int isdir, struct inode *target, struct inode *source)
+                                int isdir, struct inode *target, struct dentry *moved)
 {
+       struct inode *source = moved->d_inode;
        u32 cookie = inotify_get_cookie();
 
        if (old_dir == new_dir)
@@ -67,7 +68,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
        if (source) {
                inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
        }
-       audit_inode_child(new_name, source, new_dir);
+       audit_inode_child(new_name, moved, new_dir);
 }
 
 /*
@@ -98,7 +99,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
        inode_dir_notify(inode, DN_CREATE);
        inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
                                  dentry->d_inode);
-       audit_inode_child(dentry->d_name.name, dentry->d_inode, inode);
+       audit_inode_child(dentry->d_name.name, dentry, inode);
 }
 
 /*
@@ -109,7 +110,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
        inode_dir_notify(inode, DN_CREATE);
        inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, 
                                  dentry->d_name.name, dentry->d_inode);
-       audit_inode_child(dentry->d_name.name, dentry->d_inode, inode);
+       audit_inode_child(dentry->d_name.name, dentry, inode);
 }
 
 /*
diff --git a/include/linux/i8042.h b/include/linux/i8042.h
new file mode 100644 (file)
index 0000000..7907a72
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _LINUX_I8042_H
+#define _LINUX_I8042_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.
+ */
+
+
+/*
+ * Standard commands.
+ */
+
+#define I8042_CMD_CTL_RCTR     0x0120
+#define I8042_CMD_CTL_WCTR     0x1060
+#define I8042_CMD_CTL_TEST     0x01aa
+
+#define I8042_CMD_KBD_DISABLE  0x00ad
+#define I8042_CMD_KBD_ENABLE   0x00ae
+#define I8042_CMD_KBD_TEST     0x01ab
+#define I8042_CMD_KBD_LOOP     0x11d2
+
+#define I8042_CMD_AUX_DISABLE  0x00a7
+#define I8042_CMD_AUX_ENABLE   0x00a8
+#define I8042_CMD_AUX_TEST     0x01a9
+#define I8042_CMD_AUX_SEND     0x10d4
+#define I8042_CMD_AUX_LOOP     0x11d3
+
+#define I8042_CMD_MUX_PFX      0x0090
+#define I8042_CMD_MUX_SEND     0x1090
+
+int i8042_command(unsigned char *param, int command);
+
+#endif
index 2e4b8dd..4ed4777 100644 (file)
@@ -667,7 +667,7 @@ typedef struct hwif_s {
        u8 straight8;   /* Alan's straight 8 check */
        u8 bus_state;   /* power state of the IDE bus */
 
-       u16 host_flags;
+       u32 host_flags;
 
        u8 pio_mask;
 
index d4f48c6..742b917 100644 (file)
@@ -120,6 +120,8 @@ extern __s32 inotify_find_update_watch(struct inotify_handle *, struct inode *,
                                       u32);
 extern __s32 inotify_add_watch(struct inotify_handle *, struct inotify_watch *,
                               struct inode *, __u32);
+extern __s32 inotify_clone_watch(struct inotify_watch *, struct inotify_watch *);
+extern void inotify_evict_watch(struct inotify_watch *);
 extern int inotify_rm_watch(struct inotify_handle *, struct inotify_watch *);
 extern int inotify_rm_wd(struct inotify_handle *, __u32);
 extern void inotify_remove_watch_locked(struct inotify_handle *,
index 157ad64..8beb291 100644 (file)
@@ -1,76 +1,16 @@
 /* Things the lguest guest needs to know.  Note: like all lguest interfaces,
  * this is subject to wild and random change between versions. */
-#ifndef _ASM_LGUEST_H
-#define _ASM_LGUEST_H
+#ifndef _LINUX_LGUEST_H
+#define _LINUX_LGUEST_H
 
 #ifndef __ASSEMBLY__
+#include <linux/time.h>
 #include <asm/irq.h>
-
-#define LHCALL_FLUSH_ASYNC     0
-#define LHCALL_LGUEST_INIT     1
-#define LHCALL_CRASH           2
-#define LHCALL_LOAD_GDT                3
-#define LHCALL_NEW_PGTABLE     4
-#define LHCALL_FLUSH_TLB       5
-#define LHCALL_LOAD_IDT_ENTRY  6
-#define LHCALL_SET_STACK       7
-#define LHCALL_TS              8
-#define LHCALL_SET_CLOCKEVENT  9
-#define LHCALL_HALT            10
-#define LHCALL_BIND_DMA                12
-#define LHCALL_SEND_DMA                13
-#define LHCALL_SET_PTE         14
-#define LHCALL_SET_PMD         15
-#define LHCALL_LOAD_TLS                16
+#include <asm/lguest_hcall.h>
 
 #define LG_CLOCK_MIN_DELTA     100UL
 #define LG_CLOCK_MAX_DELTA     ULONG_MAX
 
-/*G:031 First, how does our Guest contact the Host to ask for privileged
- * operations?  There are two ways: the direct way is to make a "hypercall",
- * to make requests of the Host Itself.
- *
- * Our hypercall mechanism uses the highest unused trap code (traps 32 and
- * above are used by real hardware interrupts).  Seventeen hypercalls are
- * available: the hypercall number is put in the %eax register, and the
- * arguments (when required) are placed in %edx, %ebx and %ecx.  If a return
- * value makes sense, it's returned in %eax.
- *
- * Grossly invalid calls result in Sudden Death at the hands of the vengeful
- * Host, rather than returning failure.  This reflects Winston Churchill's
- * definition of a gentleman: "someone who is only rude intentionally". */
-#define LGUEST_TRAP_ENTRY 0x1F
-
-static inline unsigned long
-hcall(unsigned long call,
-      unsigned long arg1, unsigned long arg2, unsigned long arg3)
-{
-       /* "int" is the Intel instruction to trigger a trap. */
-       asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY)
-                      /* The call is in %eax (aka "a"), and can be replaced */
-                    : "=a"(call)
-                      /* The other arguments are in %eax, %edx, %ebx & %ecx */
-                    : "a"(call), "d"(arg1), "b"(arg2), "c"(arg3)
-                      /* "memory" means this might write somewhere in memory.
-                       * This isn't true for all calls, but it's safe to tell
-                       * gcc that it might happen so it doesn't get clever. */
-                    : "memory");
-       return call;
-}
-/*:*/
-
-void async_hcall(unsigned long call,
-                unsigned long arg1, unsigned long arg2, unsigned long arg3);
-
-/* Can't use our min() macro here: needs to be a constant */
-#define LGUEST_IRQS (NR_IRQS < 32 ? NR_IRQS: 32)
-
-#define LHCALL_RING_SIZE 64
-struct hcall_ring
-{
-       u32 eax, edx, ebx, ecx;
-};
-
 /*G:032 The second method of communicating with the Host is to via "struct
  * lguest_data".  The Guest's very first hypercall is to tell the Host where
  * this is, and then the Guest and Host both publish information in it. :*/
@@ -97,20 +37,24 @@ struct lguest_data
        /* 0xFF == done (set by Host), 0 == pending (set by Guest). */
        u8 hcall_status[LHCALL_RING_SIZE];
        /* The actual registers for the hypercalls. */
-       struct hcall_ring hcalls[LHCALL_RING_SIZE];
+       struct hcall_args hcalls[LHCALL_RING_SIZE];
 
 /* Fields initialized by the Host at boot: */
        /* Memory not to try to access */
        unsigned long reserve_mem;
-       /* ID of this Guest (used by network driver to set ethernet address) */
-       u16 guestid;
        /* KHz for the TSC clock. */
        u32 tsc_khz;
+       /* Page where the top-level pagetable is */
+       unsigned long pgdir;
 
 /* Fields initialized by the Guest at boot: */
        /* Instruction range to suppress interrupts even if enabled */
        unsigned long noirq_start, noirq_end;
+       /* Address above which page tables are all identical. */
+       unsigned long kernel_address;
+       /* The vector to try to use for system calls (0x40 or 0x80). */
+       unsigned int syscall_vec;
 };
 extern struct lguest_data lguest_data;
 #endif /* __ASSEMBLY__ */
-#endif /* _ASM_LGUEST_H */
+#endif /* _LINUX_LGUEST_H */
diff --git a/include/linux/lguest_bus.h b/include/linux/lguest_bus.h
deleted file mode 100644 (file)
index d27853d..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _ASM_LGUEST_DEVICE_H
-#define _ASM_LGUEST_DEVICE_H
-/* Everything you need to know about lguest devices. */
-#include <linux/device.h>
-#include <linux/lguest.h>
-#include <linux/lguest_launcher.h>
-
-struct lguest_device {
-       /* Unique busid, and index into lguest_page->devices[] */
-       unsigned int index;
-
-       struct device dev;
-
-       /* Driver can hang data off here. */
-       void *private;
-};
-
-/*D:380 Since interrupt numbers are arbitrary, we use a convention: each device
- * can use the interrupt number corresponding to its index.  The +1 is because
- * interrupt 0 is not usable (it's actually the timer interrupt). */
-static inline int lgdev_irq(const struct lguest_device *dev)
-{
-       return dev->index + 1;
-}
-/*:*/
-
-/* dma args must not be vmalloced! */
-void lguest_send_dma(unsigned long key, struct lguest_dma *dma);
-int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas,
-                   unsigned int num, u8 irq);
-void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas);
-
-/* Map the virtual device space */
-void *lguest_map(unsigned long phys_addr, unsigned long pages);
-void lguest_unmap(void *);
-
-struct lguest_driver {
-       const char *name;
-       struct module *owner;
-       u16 device_type;
-       int (*probe)(struct lguest_device *dev);
-       void (*remove)(struct lguest_device *dev);
-
-       struct device_driver drv;
-};
-
-extern int register_lguest_driver(struct lguest_driver *drv);
-extern void unregister_lguest_driver(struct lguest_driver *drv);
-
-extern struct lguest_device_desc *lguest_devices; /* Just past max_pfn */
-#endif /* _ASM_LGUEST_DEVICE_H */
index 6416705..61e1e3e 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_LGUEST_USER
 #define _ASM_LGUEST_USER
 /* Everything the "lguest" userspace program needs to know. */
+#include <linux/types.h>
 /* They can register up to 32 arrays of lguest_dma. */
 #define LGUEST_MAX_DMA         32
 /* At most we can dma 16 lguest_dma in one op. */
@@ -9,66 +10,6 @@
 /* How many devices?  Assume each one wants up to two dma arrays per device. */
 #define LGUEST_MAX_DEVICES (LGUEST_MAX_DMA/2)
 
-/*D:200
- * Lguest I/O
- *
- * The lguest I/O mechanism is the only way Guests can talk to devices.  There
- * are two hypercalls involved: SEND_DMA for output and BIND_DMA for input.  In
- * each case, "struct lguest_dma" describes the buffer: this contains 16
- * addr/len pairs, and if there are fewer buffer elements the len array is
- * terminated with a 0.
- *
- * I/O is organized by keys: BIND_DMA attaches buffers to a particular key, and
- * SEND_DMA transfers to buffers bound to particular key.  By convention, keys
- * correspond to a physical address within the device's page.  This means that
- * devices will never accidentally end up with the same keys, and allows the
- * Host use The Futex Trick (as we'll see later in our journey).
- *
- * SEND_DMA simply indicates a key to send to, and the physical address of the
- * "struct lguest_dma" to send.  The Host will write the number of bytes
- * transferred into the "struct lguest_dma"'s used_len member.
- *
- * BIND_DMA indicates a key to bind to, a pointer to an array of "struct
- * lguest_dma"s ready for receiving, the size of that array, and an interrupt
- * to trigger when data is received.  The Host will only allow transfers into
- * buffers with a used_len of zero: it then sets used_len to the number of
- * bytes transferred and triggers the interrupt for the Guest to process the
- * new input. */
-struct lguest_dma
-{
-       /* 0 if free to be used, filled by the Host. */
-       u32 used_len;
-       unsigned long addr[LGUEST_MAX_DMA_SECTIONS];
-       u16 len[LGUEST_MAX_DMA_SECTIONS];
-};
-/*:*/
-
-/*D:460 This is the layout of a block device memory page.  The Launcher sets up
- * the num_sectors initially to tell the Guest the size of the disk.  The Guest
- * puts the type, sector and length of the request in the first three fields,
- * then DMAs to the Host.  The Host processes the request, sets up the result,
- * then DMAs back to the Guest. */
-struct lguest_block_page
-{
-       /* 0 is a read, 1 is a write. */
-       int type;
-       u32 sector;     /* Offset in device = sector * 512. */
-       u32 bytes;      /* Length expected to be read/written in bytes */
-       /* 0 = pending, 1 = done, 2 = done, error */
-       int result;
-       u32 num_sectors; /* Disk length = num_sectors * 512 */
-};
-
-/*D:520 The network device is basically a memory page where all the Guests on
- * the network publish their MAC (ethernet) addresses: it's an array of "struct
- * lguest_net": */
-struct lguest_net
-{
-       /* Simply the mac address (with multicast bit meaning promisc). */
-       unsigned char mac[6];
-};
-/*:*/
-
 /* Where the Host expects the Guest to SEND_DMA console output to. */
 #define LGUEST_CONSOLE_DMA_KEY 0
 
@@ -81,38 +22,29 @@ struct lguest_net
  * complex burden for the Host and suboptimal for the Guest, so we have our own
  * "lguest" bus and simple drivers.
  *
- * Devices are described by an array of LGUEST_MAX_DEVICES of these structs,
- * placed by the Launcher just above the top of physical memory:
+ * Devices are described by a simplified ID, a status byte, and some "config"
+ * bytes which describe this device's configuration.  This is placed by the
+ * Launcher just above the top of physical memory:
  */
 struct lguest_device_desc {
-       /* The device type: console, network, disk etc. */
-       u16 type;
-#define LGUEST_DEVICE_T_CONSOLE        1
-#define LGUEST_DEVICE_T_NET    2
-#define LGUEST_DEVICE_T_BLOCK  3
-
-       /* The specific features of this device: these depends on device type
-        * except for LGUEST_DEVICE_F_RANDOMNESS. */
-       u16 features;
-#define LGUEST_NET_F_NOCSUM            0x4000 /* Don't bother checksumming */
-#define LGUEST_DEVICE_F_RANDOMNESS     0x8000 /* IRQ is fairly random */
-
-       /* This is how the Guest reports status of the device: the Host can set
-        * LGUEST_DEVICE_S_REMOVED to indicate removal, but the rest are only
-        * ever manipulated by the Guest, and only ever set. */
-       u16 status;
-/* 256 and above are device specific. */
-#define LGUEST_DEVICE_S_ACKNOWLEDGE    1 /* We have seen device. */
-#define LGUEST_DEVICE_S_DRIVER         2 /* We have found a driver */
-#define LGUEST_DEVICE_S_DRIVER_OK      4 /* Driver says OK! */
-#define LGUEST_DEVICE_S_REMOVED                8 /* Device has gone away. */
-#define LGUEST_DEVICE_S_REMOVED_ACK    16 /* Driver has been told. */
-#define LGUEST_DEVICE_S_FAILED         128 /* Something actually failed */
+       /* The device type: console, network, disk etc.  Type 0 terminates. */
+       __u8 type;
+       /* The number of bytes of the config array. */
+       __u8 config_len;
+       /* A status byte, written by the Guest. */
+       __u8 status;
+       __u8 config[0];
+};
 
-       /* Each device exists somewhere in Guest physical memory, over some
-        * number of pages. */
-       u16 num_pages;
-       u32 pfn;
+/*D:135 This is how we expect the device configuration field for a virtqueue
+ * (type VIRTIO_CONFIG_F_VIRTQUEUE) to be laid out: */
+struct lguest_vqconfig {
+       /* The number of entries in the virtio_ring */
+       __u16 num;
+       /* The interrupt we get when something happens. */
+       __u16 irq;
+       /* The page number of the virtio ring for this device. */
+       __u32 pfn;
 };
 /*:*/
 
@@ -120,7 +52,7 @@ struct lguest_device_desc {
 enum lguest_req
 {
        LHREQ_INITIALIZE, /* + pfnlimit, pgdir, start, pageoffset */
-       LHREQ_GETDMA, /* + addr (returns &lguest_dma, irq in ->used_len) */
+       LHREQ_GETDMA, /* No longer used */
        LHREQ_IRQ, /* + irq */
        LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */
 };
index 6c9873f..ff203dd 100644 (file)
   name:
 #endif
 
+#ifndef WEAK
+#define WEAK(name)        \
+       .weak name;        \
+       name:
+#endif
+
 #define KPROBE_ENTRY(name) \
   .pushsection .kprobes.text, "ax"; \
   ENTRY(name)
index 654ef55..33f0ff0 100644 (file)
@@ -41,18 +41,15 @@ struct memory_block {
 #define        MEM_ONLINE              (1<<0) /* exposed to userspace */
 #define        MEM_GOING_OFFLINE       (1<<1) /* exposed to userspace */
 #define        MEM_OFFLINE             (1<<2) /* exposed to userspace */
+#define        MEM_GOING_ONLINE        (1<<3)
+#define        MEM_CANCEL_ONLINE       (1<<4)
+#define        MEM_CANCEL_OFFLINE      (1<<5)
 
-/*
- * All of these states are currently kernel-internal for notifying
- * kernel components and architectures.
- *
- * For MEM_MAPPING_INVALID, all notifier chains with priority >0
- * are called before pfn_to_page() becomes invalid.  The priority=0
- * entry is reserved for the function that actually makes
- * pfn_to_page() stop working.  Any notifiers that want to be called
- * after that should have priority <0.
- */
-#define        MEM_MAPPING_INVALID     (1<<3)
+struct memory_notify {
+       unsigned long start_pfn;
+       unsigned long nr_pages;
+       int status_change_nid;
+};
 
 struct notifier_block;
 struct mem_section;
@@ -69,21 +66,31 @@ static inline int register_memory_notifier(struct notifier_block *nb)
 static inline void unregister_memory_notifier(struct notifier_block *nb)
 {
 }
+static inline int memory_notify(unsigned long val, void *v)
+{
+       return 0;
+}
 #else
+extern int register_memory_notifier(struct notifier_block *nb);
+extern void unregister_memory_notifier(struct notifier_block *nb);
 extern int register_new_memory(struct mem_section *);
 extern int unregister_memory_section(struct mem_section *);
 extern int memory_dev_init(void);
 extern int remove_memory_block(unsigned long, struct mem_section *, int);
-
+extern int memory_notify(unsigned long val, void *v);
 #define CONFIG_MEM_BLOCK_SIZE  (PAGES_PER_SECTION<<PAGE_SHIFT)
 
 
 #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
 
+#ifdef CONFIG_MEMORY_HOTPLUG
 #define hotplug_memory_notifier(fn, pri) {                     \
        static struct notifier_block fn##_mem_nb =              \
                { .notifier_call = fn, .priority = pri };       \
        register_memory_notifier(&fn##_mem_nb);                 \
 }
+#else
+#define hotplug_memory_notifier(fn, pri) do { } while (0)
+#endif
 
 #endif /* _LINUX_MEMORY_H_ */
index 3f2da44..f31bba2 100644 (file)
 #define MLX4_INIT_DOORBELL_LOCK(ptr)    do { } while (0)
 #define MLX4_GET_DOORBELL_LOCK(ptr)      (NULL)
 
-static inline void mlx4_write64_raw(__be64 val, void __iomem *dest)
-{
-       __raw_writeq((__force u64) val, dest);
-}
-
 static inline void mlx4_write64(__be32 val[2], void __iomem *dest,
                                spinlock_t *doorbell_lock)
 {
@@ -75,12 +70,6 @@ static inline void mlx4_write64(__be32 val[2], void __iomem *dest,
 #define MLX4_INIT_DOORBELL_LOCK(ptr)     spin_lock_init(ptr)
 #define MLX4_GET_DOORBELL_LOCK(ptr)      (ptr)
 
-static inline void mlx4_write64_raw(__be64 val, void __iomem *dest)
-{
-       __raw_writel(((__force u32 *) &val)[0], dest);
-       __raw_writel(((__force u32 *) &val)[1], dest + 4);
-}
-
 static inline void mlx4_write64(__be32 val[2], void __iomem *dest,
                                spinlock_t *doorbell_lock)
 {
index 522b0dd..e9fddb4 100644 (file)
@@ -361,4 +361,10 @@ struct ssb_device_id {
 #define SSB_ANY_ID             0xFFFF
 #define SSB_ANY_REV            0xFF
 
+struct virtio_device_id {
+       __u32 device;
+       __u32 vendor;
+};
+#define VIRTIO_DEV_ANY_ID      0xffffffff
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index c136abc..dd79cdb 100644 (file)
@@ -313,6 +313,10 @@ static const struct proto_ops name##_ops = {                       \
 #define MODULE_ALIAS_NET_PF_PROTO(pf, proto) \
        MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto))
 
+#define MODULE_ALIAS_NET_PF_PROTO_TYPE(pf, proto, type) \
+       MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \
+                    "-type-" __stringify(type))
+
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 extern ctl_table net_table[];
index 6f85db3..4a3f54e 100644 (file)
@@ -996,7 +996,7 @@ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index)
  *
  * Check individual transmit queue of a device with multiple transmit queues.
  */
-static inline int netif_subqueue_stopped(const struct net_device *dev,
+static inline int __netif_subqueue_stopped(const struct net_device *dev,
                                         u16 queue_index)
 {
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
@@ -1007,6 +1007,11 @@ static inline int netif_subqueue_stopped(const struct net_device *dev,
 #endif
 }
 
+static inline int netif_subqueue_stopped(const struct net_device *dev,
+                                        struct sk_buff *skb)
+{
+       return __netif_subqueue_stopped(dev, skb_get_queue_mapping(skb));
+}
 
 /**
  *     netif_wake_subqueue - allow sending packets on subqueue
index 768b933..5d2281f 100644 (file)
@@ -141,6 +141,7 @@ struct pci_dev {
        unsigned int    class;          /* 3 bytes: (base,sub,prog-if) */
        u8              revision;       /* PCI revision, low byte of class word */
        u8              hdr_type;       /* PCI header type (`multi' flag masked out) */
+       u8              pcie_type;      /* PCI-E device/port type */
        u8              rom_base_reg;   /* which config register controls the ROM */
        u8              pin;            /* which interrupt pin this device uses */
 
@@ -183,6 +184,7 @@ struct pci_dev {
        unsigned int    msi_enabled:1;
        unsigned int    msix_enabled:1;
        unsigned int    is_managed:1;
+       unsigned int    is_pcie:1;
        atomic_t        enable_cnt;     /* pci_enable_device has been called */
 
        u32             saved_config_space[16]; /* config space saved at suspend time */
index df948b4..4e10a07 100644 (file)
 #define PCI_DEVICE_ID_TIGON3_5720      0x1658
 #define PCI_DEVICE_ID_TIGON3_5721      0x1659
 #define PCI_DEVICE_ID_TIGON3_5722      0x165a
+#define PCI_DEVICE_ID_TIGON3_5723      0x165b
 #define PCI_DEVICE_ID_TIGON3_5705M     0x165d
 #define PCI_DEVICE_ID_TIGON3_5705M_2   0x165e
 #define PCI_DEVICE_ID_TIGON3_5714      0x1668
index 72bfccd..422eab4 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/reiserfs_fs_sb.h>
 #endif
 
+struct fid;
+
 /*
  *  include/linux/reiser_fs.h
  *
@@ -1877,12 +1879,10 @@ void reiserfs_delete_inode(struct inode *inode);
 int reiserfs_write_inode(struct inode *inode, int);
 int reiserfs_get_block(struct inode *inode, sector_t block,
                       struct buffer_head *bh_result, int create);
-struct dentry *reiserfs_get_dentry(struct super_block *, void *);
-struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 * data,
-                                 int len, int fhtype,
-                                 int (*acceptable) (void *contect,
-                                                    struct dentry * de),
-                                 void *context);
+struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+                                    int fh_len, int fh_type);
+struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
+                                    int fh_len, int fh_type);
 int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
                       int connectable);
 
index 2dc7464..df7ddce 100644 (file)
 #include <asm/scatterlist.h>
 #include <linux/mm.h>
 #include <linux/string.h>
+#include <asm/io.h>
 
+/*
+ * Notes on SG table design.
+ *
+ * Architectures must provide an unsigned long page_link field in the
+ * scatterlist struct. We use that to place the page pointer AND encode
+ * information about the sg table as well. The two lower bits are reserved
+ * for this information.
+ *
+ * If bit 0 is set, then the page_link contains a pointer to the next sg
+ * table list. Otherwise the next entry is at sg + 1.
+ *
+ * If bit 1 is set, then this sg entry is the last element in a list.
+ *
+ * See sg_next().
+ *
+ */
+
+#define SG_MAGIC       0x87654321
+
+/**
+ * sg_set_page - Set sg entry to point at given page
+ * @sg:                 SG entry
+ * @page:       The page
+ *
+ * Description:
+ *   Use this function to set an sg entry pointing at a page, never assign
+ *   the page directly. We encode sg table information in the lower bits
+ *   of the page pointer. See sg_page() for looking up the page belonging
+ *   to an sg entry.
+ *
+ **/
+static inline void sg_set_page(struct scatterlist *sg, struct page *page)
+{
+       unsigned long page_link = sg->page_link & 0x3;
+
+       /*
+        * In order for the low bit stealing approach to work, pages
+        * must be aligned at a 32-bit boundary as a minimum.
+        */
+       BUG_ON((unsigned long) page & 0x03);
+#ifdef CONFIG_DEBUG_SG
+       BUG_ON(sg->sg_magic != SG_MAGIC);
+#endif
+       sg->page_link = page_link | (unsigned long) page;
+}
+
+#define sg_page(sg)    ((struct page *) ((sg)->page_link & ~0x3))
+
+/**
+ * sg_set_buf - Set sg entry to point at given data
+ * @sg:                 SG entry
+ * @buf:        Data
+ * @buflen:     Data length
+ *
+ **/
 static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
                              unsigned int buflen)
 {
-       sg->page = virt_to_page(buf);
+       sg_set_page(sg, virt_to_page(buf));
        sg->offset = offset_in_page(buf);
        sg->length = buflen;
 }
 
-static inline void sg_init_one(struct scatterlist *sg, const void *buf,
-                              unsigned int buflen)
-{
-       memset(sg, 0, sizeof(*sg));
-       sg_set_buf(sg, buf, buflen);
-}
-
 /*
  * We overload the LSB of the page pointer to indicate whether it's
  * a valid sg entry, or whether it points to the start of a new scatterlist.
  * Those low bits are there for everyone! (thanks mason :-)
  */
-#define sg_is_chain(sg)                ((unsigned long) (sg)->page & 0x01)
+#define sg_is_chain(sg)                ((sg)->page_link & 0x01)
+#define sg_is_last(sg)         ((sg)->page_link & 0x02)
 #define sg_chain_ptr(sg)       \
-       ((struct scatterlist *) ((unsigned long) (sg)->page & ~0x01))
+       ((struct scatterlist *) ((sg)->page_link & ~0x03))
 
 /**
  * sg_next - return the next scatterlist entry in a list
  * @sg:                The current sg entry
  *
- * Usually the next entry will be @sg@ + 1, but if this sg element is part
- * of a chained scatterlist, it could jump to the start of a new
- * scatterlist array.
- *
- * Note that the caller must ensure that there are further entries after
- * the current entry, this function will NOT return NULL for an end-of-list.
+ * Description:
+ *   Usually the next entry will be @sg@ + 1, but if this sg element is part
+ *   of a chained scatterlist, it could jump to the start of a new
+ *   scatterlist array.
  *
- */
+ **/
 static inline struct scatterlist *sg_next(struct scatterlist *sg)
 {
-       sg++;
+#ifdef CONFIG_DEBUG_SG
+       BUG_ON(sg->sg_magic != SG_MAGIC);
+#endif
+       if (sg_is_last(sg))
+               return NULL;
 
+       sg++;
        if (unlikely(sg_is_chain(sg)))
                sg = sg_chain_ptr(sg);
 
@@ -62,14 +115,15 @@ static inline struct scatterlist *sg_next(struct scatterlist *sg)
  * @sgl:       First entry in the scatterlist
  * @nents:     Number of entries in the scatterlist
  *
- * Should only be used casually, it (currently) scan the entire list
- * to get the last entry.
+ * Description:
+ *   Should only be used casually, it (currently) scan the entire list
+ *   to get the last entry.
  *
- * Note that the @sgl@ pointer passed in need not be the first one,
- * the important bit is that @nents@ denotes the number of entries that
- * exist from @sgl@.
+ *   Note that the @sgl@ pointer passed in need not be the first one,
+ *   the important bit is that @nents@ denotes the number of entries that
+ *   exist from @sgl@.
  *
- */
+ **/
 static inline struct scatterlist *sg_last(struct scatterlist *sgl,
                                          unsigned int nents)
 {
@@ -82,6 +136,10 @@ static inline struct scatterlist *sg_last(struct scatterlist *sgl,
        for_each_sg(sgl, sg, nents, i)
                ret = sg;
 
+#endif
+#ifdef CONFIG_DEBUG_SG
+       BUG_ON(sgl[0].sg_magic != SG_MAGIC);
+       BUG_ON(!sg_is_last(ret));
 #endif
        return ret;
 }
@@ -92,16 +150,111 @@ static inline struct scatterlist *sg_last(struct scatterlist *sgl,
  * @prv_nents: Number of entries in prv
  * @sgl:       Second scatterlist
  *
- * Links @prv@ and @sgl@ together, to form a longer scatterlist.
+ * Description:
+ *   Links @prv@ and @sgl@ together, to form a longer scatterlist.
  *
- */
+ **/
 static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
                            struct scatterlist *sgl)
 {
 #ifndef ARCH_HAS_SG_CHAIN
        BUG();
 #endif
-       prv[prv_nents - 1].page = (struct page *) ((unsigned long) sgl | 0x01);
+       prv[prv_nents - 1].page_link = (unsigned long) sgl | 0x01;
+}
+
+/**
+ * sg_mark_end - Mark the end of the scatterlist
+ * @sgl:       Scatterlist
+ * @nents:     Number of entries in sgl
+ *
+ * Description:
+ *   Marks the last entry as the termination point for sg_next()
+ *
+ **/
+static inline void sg_mark_end(struct scatterlist *sgl, unsigned int nents)
+{
+       sgl[nents - 1].page_link = 0x02;
+}
+
+static inline void __sg_mark_end(struct scatterlist *sg)
+{
+       sg->page_link |= 0x02;
+}
+
+/**
+ * sg_init_one - Initialize a single entry sg list
+ * @sg:                 SG entry
+ * @buf:        Virtual address for IO
+ * @buflen:     IO length
+ *
+ * Notes:
+ *   This should not be used on a single entry that is part of a larger
+ *   table. Use sg_init_table() for that.
+ *
+ **/
+static inline void sg_init_one(struct scatterlist *sg, const void *buf,
+                              unsigned int buflen)
+{
+       memset(sg, 0, sizeof(*sg));
+#ifdef CONFIG_DEBUG_SG
+       sg->sg_magic = SG_MAGIC;
+#endif
+       sg_mark_end(sg, 1);
+       sg_set_buf(sg, buf, buflen);
+}
+
+/**
+ * sg_init_table - Initialize SG table
+ * @sgl:          The SG table
+ * @nents:        Number of entries in table
+ *
+ * Notes:
+ *   If this is part of a chained sg table, sg_mark_end() should be
+ *   used only on the last table part.
+ *
+ **/
+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
+{
+       memset(sgl, 0, sizeof(*sgl) * nents);
+       sg_mark_end(sgl, nents);
+#ifdef CONFIG_DEBUG_SG
+       {
+               int i;
+               for (i = 0; i < nents; i++)
+                       sgl[i].sg_magic = SG_MAGIC;
+       }
+#endif
+}
+
+/**
+ * sg_phys - Return physical address of an sg entry
+ * @sg:             SG entry
+ *
+ * Description:
+ *   This calls page_to_phys() on the page in this sg entry, and adds the
+ *   sg offset. The caller must know that it is legal to call page_to_phys()
+ *   on the sg page.
+ *
+ **/
+static inline unsigned long sg_phys(struct scatterlist *sg)
+{
+       return page_to_phys(sg_page(sg)) + sg->offset;
+}
+
+/**
+ * sg_virt - Return virtual address of an sg entry
+ * @sg:      SG entry
+ *
+ * Description:
+ *   This calls page_address() on the page in this sg entry, and adds the
+ *   sg offset. The caller must know that the sg page has a valid virtual
+ *   mapping.
+ *
+ **/
+static inline void *sg_virt(struct scatterlist *sg)
+{
+       return page_address(sg_page(sg)) + sg->offset;
 }
 
 #endif /* _LINUX_SCATTERLIST_H */
index ba81ffe..827b85b 100644 (file)
@@ -8,45 +8,43 @@
  */
 
 struct screen_info {
-       u8  orig_x;             /* 0x00 */
-       u8  orig_y;             /* 0x01 */
-       u16 ext_mem_k;          /* 0x02 */
-       u16 orig_video_page;    /* 0x04 */
-       u8  orig_video_mode;    /* 0x06 */
-       u8  orig_video_cols;    /* 0x07 */
-       u16 unused2;            /* 0x08 */
-       u16 orig_video_ega_bx;  /* 0x0a */
-       u16 unused3;            /* 0x0c */
-       u8  orig_video_lines;   /* 0x0e */
-       u8  orig_video_isVGA;   /* 0x0f */
-       u16 orig_video_points;  /* 0x10 */
+       __u8  orig_x;           /* 0x00 */
+       __u8  orig_y;           /* 0x01 */
+       __u16 ext_mem_k;        /* 0x02 */
+       __u16 orig_video_page;  /* 0x04 */
+       __u8  orig_video_mode;  /* 0x06 */
+       __u8  orig_video_cols;  /* 0x07 */
+       __u16 unused2;          /* 0x08 */
+       __u16 orig_video_ega_bx;/* 0x0a */
+       __u16 unused3;          /* 0x0c */
+       __u8  orig_video_lines; /* 0x0e */
+       __u8  orig_video_isVGA; /* 0x0f */
+       __u16 orig_video_points;/* 0x10 */
 
        /* VESA graphic mode -- linear frame buffer */
-       u16 lfb_width;          /* 0x12 */
-       u16 lfb_height;         /* 0x14 */
-       u16 lfb_depth;          /* 0x16 */
-       u32 lfb_base;           /* 0x18 */
-       u32 lfb_size;           /* 0x1c */
-       u16 cl_magic, cl_offset; /* 0x20 */
-       u16 lfb_linelength;     /* 0x24 */
-       u8  red_size;           /* 0x26 */
-       u8  red_pos;            /* 0x27 */
-       u8  green_size;         /* 0x28 */
-       u8  green_pos;          /* 0x29 */
-       u8  blue_size;          /* 0x2a */
-       u8  blue_pos;           /* 0x2b */
-       u8  rsvd_size;          /* 0x2c */
-       u8  rsvd_pos;           /* 0x2d */
-       u16 vesapm_seg;         /* 0x2e */
-       u16 vesapm_off;         /* 0x30 */
-       u16 pages;              /* 0x32 */
-       u16 vesa_attributes;    /* 0x34 */
-       u32 capabilities;       /* 0x36 */
-       u8  _reserved[6];       /* 0x3a */
+       __u16 lfb_width;        /* 0x12 */
+       __u16 lfb_height;       /* 0x14 */
+       __u16 lfb_depth;        /* 0x16 */
+       __u32 lfb_base;         /* 0x18 */
+       __u32 lfb_size;         /* 0x1c */
+       __u16 cl_magic, cl_offset; /* 0x20 */
+       __u16 lfb_linelength;   /* 0x24 */
+       __u8  red_size;         /* 0x26 */
+       __u8  red_pos;          /* 0x27 */
+       __u8  green_size;       /* 0x28 */
+       __u8  green_pos;        /* 0x29 */
+       __u8  blue_size;        /* 0x2a */
+       __u8  blue_pos;         /* 0x2b */
+       __u8  rsvd_size;        /* 0x2c */
+       __u8  rsvd_pos;         /* 0x2d */
+       __u16 vesapm_seg;       /* 0x2e */
+       __u16 vesapm_off;       /* 0x30 */
+       __u16 pages;            /* 0x32 */
+       __u16 vesa_attributes;  /* 0x34 */
+       __u32 capabilities;     /* 0x36 */
+       __u8  _reserved[6];     /* 0x3a */
 } __attribute__((packed));
 
-extern struct screen_info screen_info;
-
 #define VIDEO_TYPE_MDA         0x10    /* Monochrome Text Display      */
 #define VIDEO_TYPE_CGA         0x11    /* CGA Display                  */
 #define VIDEO_TYPE_EGAM                0x20    /* EGA/VGA in Monochrome Mode   */
@@ -65,4 +63,17 @@ extern struct screen_info screen_info;
 
 #define VIDEO_TYPE_PMAC                0x60    /* PowerMacintosh frame buffer. */
 
+#ifdef __KERNEL__
+extern struct screen_info screen_info;
+
+#define ORIG_X                 (screen_info.orig_x)
+#define ORIG_Y                 (screen_info.orig_y)
+#define ORIG_VIDEO_MODE                (screen_info.orig_video_mode)
+#define ORIG_VIDEO_COLS        (screen_info.orig_video_cols)
+#define ORIG_VIDEO_EGA_BX      (screen_info.orig_video_ega_bx)
+#define ORIG_VIDEO_LINES       (screen_info.orig_video_lines)
+#define ORIG_VIDEO_ISVGA       (screen_info.orig_video_isVGA)
+#define ORIG_VIDEO_POINTS       (screen_info.orig_video_points)
+#endif /* __KERNEL__ */
+
 #endif /* _SCREEN_INFO_H */
index f93f22b..fd4e12f 100644 (file)
@@ -41,8 +41,7 @@
 #define SKB_DATA_ALIGN(X)      (((X) + (SMP_CACHE_BYTES - 1)) & \
                                 ~(SMP_CACHE_BYTES - 1))
 #define SKB_WITH_OVERHEAD(X)   \
-       (((X) - sizeof(struct skb_shared_info)) & \
-        ~(SMP_CACHE_BYTES - 1))
+       ((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 #define SKB_MAX_ORDER(X, ORDER) \
        SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X))
 #define SKB_MAX_HEAD(X)                (SKB_MAX_ORDER((X), 0))
@@ -301,8 +300,9 @@ struct sk_buff {
 #endif
 
        int                     iif;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
        __u16                   queue_mapping;
-
+#endif
 #ifdef CONFIG_NET_SCHED
        __u16                   tc_index;       /* traffic control index */
 #ifdef CONFIG_NET_CLS_ACT
@@ -1770,6 +1770,15 @@ static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping)
 #endif
 }
 
+static inline u16 skb_get_queue_mapping(struct sk_buff *skb)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       return skb->queue_mapping;
+#else
+       return 0;
+#endif
+}
+
 static inline void skb_copy_queue_mapping(struct sk_buff *to, const struct sk_buff *from)
 {
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
index f852e1a..c22ef1c 100644 (file)
@@ -291,6 +291,7 @@ struct ucred {
 #define SOL_TIPC       271
 #define SOL_RXRPC      272
 #define SOL_PPPOL2TP   273
+#define SOL_BLUETOOTH  274
 
 /* IPX options */
 #define IPX_TYPE       1
index 8dba97a..52e3d5f 100644 (file)
@@ -294,48 +294,6 @@ struct video_code
 #define VID_PLAY_RESET                 13
 #define VID_PLAY_END_MARK              14
 
-
-
-#define VID_HARDWARE_BT848     1
-#define VID_HARDWARE_QCAM_BW   2
-#define VID_HARDWARE_PMS       3
-#define VID_HARDWARE_QCAM_C    4
-#define VID_HARDWARE_PSEUDO    5
-#define VID_HARDWARE_SAA5249   6
-#define VID_HARDWARE_AZTECH    7
-#define VID_HARDWARE_SF16MI    8
-#define VID_HARDWARE_RTRACK    9
-#define VID_HARDWARE_ZOLTRIX   10
-#define VID_HARDWARE_SAA7146    11
-#define VID_HARDWARE_VIDEUM    12      /* Reserved for Winnov videum */
-#define VID_HARDWARE_RTRACK2   13
-#define VID_HARDWARE_PERMEDIA2 14      /* Reserved for Permedia2 */
-#define VID_HARDWARE_RIVA128   15      /* Reserved for RIVA 128 */
-#define VID_HARDWARE_PLANB     16      /* PowerMac motherboard video-in */
-#define VID_HARDWARE_BROADWAY  17      /* Broadway project */
-#define VID_HARDWARE_GEMTEK    18
-#define VID_HARDWARE_TYPHOON   19
-#define VID_HARDWARE_VINO      20      /* SGI Indy Vino */
-#define VID_HARDWARE_CADET     21      /* Cadet radio */
-#define VID_HARDWARE_TRUST     22      /* Trust FM Radio */
-#define VID_HARDWARE_TERRATEC  23      /* TerraTec ActiveRadio */
-#define VID_HARDWARE_CPIA      24
-#define VID_HARDWARE_ZR36120   25      /* Zoran ZR36120/ZR36125 */
-#define VID_HARDWARE_ZR36067   26      /* Zoran ZR36067/36060 */
-#define VID_HARDWARE_OV511     27
-#define VID_HARDWARE_ZR356700  28      /* Zoran 36700 series */
-#define VID_HARDWARE_W9966     29
-#define VID_HARDWARE_SE401     30      /* SE401 USB webcams */
-#define VID_HARDWARE_PWC       31      /* Philips webcams */
-#define VID_HARDWARE_MEYE      32      /* Sony Vaio MotionEye cameras */
-#define VID_HARDWARE_CPIA2     33
-#define VID_HARDWARE_VICAM      34
-#define VID_HARDWARE_SF16FMR2  35
-#define VID_HARDWARE_W9968CF   36
-#define VID_HARDWARE_SAA7114H   37
-#define VID_HARDWARE_SN9C102   38
-#define VID_HARDWARE_ARV       39
-
 #endif /* CONFIG_VIDEO_V4L1_COMPAT */
 
 #endif /* __LINUX_VIDEODEV_H */
index 1f503e9..439474f 100644 (file)
@@ -441,94 +441,6 @@ struct v4l2_timecode
 #define V4L2_TC_USERBITS_8BITCHARS     0x0008
 /* The above is based on SMPTE timecodes */
 
-#ifdef __KERNEL__
-/*
- *     M P E G   C O M P R E S S I O N   P A R A M E T E R S
- *
- *  ### WARNING: This experimental MPEG compression API is obsolete.
- *  ###          It is replaced by the MPEG controls API.
- *  ###          This old API will disappear in the near future!
- *
- */
-enum v4l2_bitrate_mode {
-       V4L2_BITRATE_NONE = 0,  /* not specified */
-       V4L2_BITRATE_CBR,       /* constant bitrate */
-       V4L2_BITRATE_VBR,       /* variable bitrate */
-};
-struct v4l2_bitrate {
-       /* rates are specified in kbit/sec */
-       enum v4l2_bitrate_mode  mode;
-       __u32                   min;
-       __u32                   target;  /* use this one for CBR */
-       __u32                   max;
-};
-
-enum v4l2_mpeg_streamtype {
-       V4L2_MPEG_SS_1,         /* MPEG-1 system stream */
-       V4L2_MPEG_PS_2,         /* MPEG-2 program stream */
-       V4L2_MPEG_TS_2,         /* MPEG-2 transport stream */
-       V4L2_MPEG_PS_DVD,       /* MPEG-2 program stream with DVD header fixups */
-};
-enum v4l2_mpeg_audiotype {
-       V4L2_MPEG_AU_2_I,       /* MPEG-2 layer 1 */
-       V4L2_MPEG_AU_2_II,      /* MPEG-2 layer 2 */
-       V4L2_MPEG_AU_2_III,     /* MPEG-2 layer 3 */
-       V4L2_MPEG_AC3,          /* AC3 */
-       V4L2_MPEG_LPCM,         /* LPCM */
-};
-enum v4l2_mpeg_videotype {
-       V4L2_MPEG_VI_1,         /* MPEG-1 */
-       V4L2_MPEG_VI_2,         /* MPEG-2 */
-};
-enum v4l2_mpeg_aspectratio {
-       V4L2_MPEG_ASPECT_SQUARE = 1,   /* square pixel */
-       V4L2_MPEG_ASPECT_4_3    = 2,   /*  4 : 3       */
-       V4L2_MPEG_ASPECT_16_9   = 3,   /* 16 : 9       */
-       V4L2_MPEG_ASPECT_1_221  = 4,   /*  1 : 2,21    */
-};
-
-struct v4l2_mpeg_compression {
-       /* general */
-       enum v4l2_mpeg_streamtype       st_type;
-       struct v4l2_bitrate             st_bitrate;
-
-       /* transport streams */
-       __u16                           ts_pid_pmt;
-       __u16                           ts_pid_audio;
-       __u16                           ts_pid_video;
-       __u16                           ts_pid_pcr;
-
-       /* program stream */
-       __u16                           ps_size;
-       __u16                           reserved_1;    /* align */
-
-       /* audio */
-       enum v4l2_mpeg_audiotype        au_type;
-       struct v4l2_bitrate             au_bitrate;
-       __u32                           au_sample_rate;
-       __u8                            au_pesid;
-       __u8                            reserved_2[3]; /* align */
-
-       /* video */
-       enum v4l2_mpeg_videotype        vi_type;
-       enum v4l2_mpeg_aspectratio      vi_aspect_ratio;
-       struct v4l2_bitrate             vi_bitrate;
-       __u32                           vi_frame_rate;
-       __u16                           vi_frames_per_gop;
-       __u16                           vi_bframes_count;
-       __u8                            vi_pesid;
-       __u8                            reserved_3[3]; /* align */
-
-       /* misc flags */
-       __u32                           closed_gops:1;
-       __u32                           pulldown:1;
-       __u32                           reserved_4:30; /* align */
-
-       /* I don't expect the above being perfect yet ;) */
-       __u32                           reserved_5[8];
-};
-#endif
-
 struct v4l2_jpegcompression
 {
        int quality;
@@ -1420,10 +1332,6 @@ struct v4l2_chip_ident {
 #define VIDIOC_ENUM_FMT         _IOWR ('V',  2, struct v4l2_fmtdesc)
 #define VIDIOC_G_FMT           _IOWR ('V',  4, struct v4l2_format)
 #define VIDIOC_S_FMT           _IOWR ('V',  5, struct v4l2_format)
-#ifdef __KERNEL__
-#define VIDIOC_G_MPEGCOMP       _IOR  ('V',  6, struct v4l2_mpeg_compression)
-#define VIDIOC_S_MPEGCOMP      _IOW  ('V',  7, struct v4l2_mpeg_compression)
-#endif
 #define VIDIOC_REQBUFS         _IOWR ('V',  8, struct v4l2_requestbuffers)
 #define VIDIOC_QUERYBUF                _IOWR ('V',  9, struct v4l2_buffer)
 #define VIDIOC_G_FBUF          _IOR  ('V', 10, struct v4l2_framebuffer)
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
new file mode 100644 (file)
index 0000000..14e1379
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef _LINUX_VIRTIO_H
+#define _LINUX_VIRTIO_H
+/* Everything a virtio driver needs to work with any particular virtio
+ * implementation. */
+#include <linux/types.h>
+#include <linux/scatterlist.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+/**
+ * virtqueue - a queue to register buffers for sending or receiving.
+ * @callback: the function to call when buffers are consumed (can be NULL).
+ *    If this returns false, callbacks are suppressed until vq_ops->restart
+ *    is called.
+ * @vdev: the virtio device this queue was created for.
+ * @vq_ops: the operations for this virtqueue (see below).
+ * @priv: a pointer for the virtqueue implementation to use.
+ */
+struct virtqueue
+{
+       bool (*callback)(struct virtqueue *vq);
+       struct virtio_device *vdev;
+       struct virtqueue_ops *vq_ops;
+       void *priv;
+};
+
+/**
+ * virtqueue_ops - operations for virtqueue abstraction layer
+ * @add_buf: expose buffer to other end
+ *     vq: the struct virtqueue we're talking about.
+ *     sg: the description of the buffer(s).
+ *     out_num: the number of sg readable by other side
+ *     in_num: the number of sg which are writable (after readable ones)
+ *     data: the token identifying the buffer.
+ *      Returns 0 or an error.
+ * @kick: update after add_buf
+ *     vq: the struct virtqueue
+ *     After one or more add_buf calls, invoke this to kick the other side.
+ * @get_buf: get the next used buffer
+ *     vq: the struct virtqueue we're talking about.
+ *     len: the length written into the buffer
+ *     Returns NULL or the "data" token handed to add_buf.
+ * @restart: restart callbacks after callback returned false.
+ *     vq: the struct virtqueue we're talking about.
+ *     This returns "false" (and doesn't re-enable) if there are pending
+ *     buffers in the queue, to avoid a race.
+ * @shutdown: "unadd" all buffers.
+ *     vq: the struct virtqueue we're talking about.
+ *     Remove everything from the queue.
+ *
+ * Locking rules are straightforward: the driver is responsible for
+ * locking.  No two operations may be invoked simultaneously.
+ *
+ * All operations can be called in any context.
+ */
+struct virtqueue_ops {
+       int (*add_buf)(struct virtqueue *vq,
+                      struct scatterlist sg[],
+                      unsigned int out_num,
+                      unsigned int in_num,
+                      void *data);
+
+       void (*kick)(struct virtqueue *vq);
+
+       void *(*get_buf)(struct virtqueue *vq, unsigned int *len);
+
+       bool (*restart)(struct virtqueue *vq);
+
+       void (*shutdown)(struct virtqueue *vq);
+};
+
+/**
+ * virtio_device - representation of a device using virtio
+ * @index: unique position on the virtio bus
+ * @dev: underlying device.
+ * @id: the device type identification (used to match it with a driver).
+ * @config: the configuration ops for this device.
+ * @priv: private pointer for the driver's use.
+ */
+struct virtio_device
+{
+       int index;
+       struct device dev;
+       struct virtio_device_id id;
+       struct virtio_config_ops *config;
+       void *priv;
+};
+
+int register_virtio_device(struct virtio_device *dev);
+void unregister_virtio_device(struct virtio_device *dev);
+
+/**
+ * virtio_driver - operations for a virtio I/O driver
+ * @driver: underlying device driver (populate name and owner).
+ * @id_table: the ids serviced by this driver.
+ * @probe: the function to call when a device is found.  Returns a token for
+ *    remove, or PTR_ERR().
+ * @remove: the function when a device is removed.
+ */
+struct virtio_driver {
+       struct device_driver driver;
+       const struct virtio_device_id *id_table;
+       int (*probe)(struct virtio_device *dev);
+       void (*remove)(struct virtio_device *dev);
+};
+
+int register_virtio_driver(struct virtio_driver *drv);
+void unregister_virtio_driver(struct virtio_driver *drv);
+#endif /* _LINUX_VIRTIO_H */
diff --git a/include/linux/virtio_9p.h b/include/linux/virtio_9p.h
new file mode 100644 (file)
index 0000000..8eff0b5
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _LINUX_VIRTIO_9P_H
+#define _LINUX_VIRTIO_9P_H
+#include <linux/virtio_config.h>
+
+/* The ID for virtio console */
+#define VIRTIO_ID_9P   9
+/* Maximum number of virtio channels per partition (1 for now) */
+#define MAX_9P_CHAN    1
+
+#endif /* _LINUX_VIRTIO_9P_H */
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
new file mode 100644 (file)
index 0000000..7bd2bce
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _LINUX_VIRTIO_BLK_H
+#define _LINUX_VIRTIO_BLK_H
+#include <linux/virtio_config.h>
+
+/* The ID for virtio_block */
+#define VIRTIO_ID_BLOCK        2
+
+/* Feature bits */
+#define VIRTIO_CONFIG_BLK_F    0x40
+#define VIRTIO_BLK_F_BARRIER   1       /* Does host support barriers? */
+
+/* The capacity (in 512-byte sectors). */
+#define VIRTIO_CONFIG_BLK_F_CAPACITY   0x41
+/* The maximum segment size. */
+#define VIRTIO_CONFIG_BLK_F_SIZE_MAX   0x42
+/* The maximum number of segments. */
+#define VIRTIO_CONFIG_BLK_F_SEG_MAX    0x43
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN                0
+#define VIRTIO_BLK_T_OUT       1
+
+/* This bit says it's a scsi command, not an actual read or write. */
+#define VIRTIO_BLK_T_SCSI_CMD  2
+
+/* Barrier before this op. */
+#define VIRTIO_BLK_T_BARRIER   0x80000000
+
+/* This is the first element of the read scatter-gather list. */
+struct virtio_blk_outhdr
+{
+       /* VIRTIO_BLK_T* */
+       __u32 type;
+       /* io priority. */
+       __u32 ioprio;
+       /* Sector (ie. 512 byte offset) */
+       __u64 sector;
+       /* Where to put reply. */
+       __u64 id;
+};
+
+#define VIRTIO_BLK_S_OK                0
+#define VIRTIO_BLK_S_IOERR     1
+#define VIRTIO_BLK_S_UNSUPP    2
+
+/* This is the first element of the write scatter-gather list */
+struct virtio_blk_inhdr
+{
+       unsigned char status;
+};
+#endif /* _LINUX_VIRTIO_BLK_H */
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
new file mode 100644 (file)
index 0000000..bcc0188
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef _LINUX_VIRTIO_CONFIG_H
+#define _LINUX_VIRTIO_CONFIG_H
+/* Virtio devices use a standardized configuration space to define their
+ * features and pass configuration information, but each implementation can
+ * store and access that space differently. */
+#include <linux/types.h>
+
+/* Status byte for guest to report progress, and synchronize config. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE    1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER         2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK      4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED         0x80
+
+/* Feature byte (actually 7 bits availabe): */
+/* Requirements/features of the virtio implementation. */
+#define VIRTIO_CONFIG_F_VIRTIO 1
+/* Requirements/features of the virtqueue (may have more than one). */
+#define VIRTIO_CONFIG_F_VIRTQUEUE 2
+
+#ifdef __KERNEL__
+struct virtio_device;
+
+/**
+ * virtio_config_ops - operations for configuring a virtio device
+ * @find: search for the next configuration field of the given type.
+ *     vdev: the virtio_device
+ *     type: the feature type
+ *     len: the (returned) length of the field if found.
+ *     Returns a token if found, or NULL.  Never returnes the same field twice
+ *     (ie. it's used up).
+ * @get: read the value of a configuration field after find().
+ *     vdev: the virtio_device
+ *     token: the token returned from find().
+ *     buf: the buffer to write the field value into.
+ *     len: the length of the buffer (given by find()).
+ *     Note that contents are conventionally little-endian.
+ * @set: write the value of a configuration field after find().
+ *     vdev: the virtio_device
+ *     token: the token returned from find().
+ *     buf: the buffer to read the field value from.
+ *     len: the length of the buffer (given by find()).
+ *     Note that contents are conventionally little-endian.
+ * @get_status: read the status byte
+ *     vdev: the virtio_device
+ *     Returns the status byte
+ * @set_status: write the status byte
+ *     vdev: the virtio_device
+ *     status: the new status byte
+ * @find_vq: find the first VIRTIO_CONFIG_F_VIRTQUEUE and create a virtqueue.
+ *     vdev: the virtio_device
+ *     callback: the virqtueue callback
+ *     Returns the new virtqueue or ERR_PTR().
+ * @del_vq: free a virtqueue found by find_vq().
+ */
+struct virtio_config_ops
+{
+       void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len);
+       void (*get)(struct virtio_device *vdev, void *token,
+                   void *buf, unsigned len);
+       void (*set)(struct virtio_device *vdev, void *token,
+                   const void *buf, unsigned len);
+       u8 (*get_status)(struct virtio_device *vdev);
+       void (*set_status)(struct virtio_device *vdev, u8 status);
+       struct virtqueue *(*find_vq)(struct virtio_device *vdev,
+                                    bool (*callback)(struct virtqueue *));
+       void (*del_vq)(struct virtqueue *vq);
+};
+
+/**
+ * virtio_config_val - get a single virtio config and mark it used.
+ * @config: the virtio config space
+ * @type: the type to search for.
+ * @val: a pointer to the value to fill in.
+ *
+ * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't
+ * be found again.  This version does endian conversion. */
+#define virtio_config_val(vdev, type, v) ({                            \
+       int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \
+                                                                       \
+       BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2             \
+                    && sizeof(*(v)) != 4 && sizeof(*(v)) != 8);        \
+       if (!_err) {                                                    \
+               switch (sizeof(*(v))) {                                 \
+               case 2: le16_to_cpus((__u16 *) v); break;               \
+               case 4: le32_to_cpus((__u32 *) v); break;               \
+               case 8: le64_to_cpus((__u64 *) v); break;               \
+               }                                                       \
+       }                                                               \
+       _err;                                                           \
+})
+
+int __virtio_config_val(struct virtio_device *dev,
+                       u8 type, void *val, size_t size);
+
+/**
+ * virtio_use_bit - helper to use a feature bit in a bitfield value.
+ * @dev: the virtio device
+ * @token: the token as returned from vdev->config->find().
+ * @len: the length of the field.
+ * @bitnum: the bit to test.
+ *
+ * If handed a NULL token, it returns false, otherwise returns bit status.
+ * If it's one, it sets the mirroring acknowledgement bit. */
+int virtio_use_bit(struct virtio_device *vdev,
+                  void *token, unsigned int len, unsigned int bitnum);
+#endif /* __KERNEL__ */
+#endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
new file mode 100644 (file)
index 0000000..ed2d4ea
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _LINUX_VIRTIO_CONSOLE_H
+#define _LINUX_VIRTIO_CONSOLE_H
+#include <linux/virtio_config.h>
+
+/* The ID for virtio console */
+#define VIRTIO_ID_CONSOLE      3
+
+#ifdef __KERNEL__
+int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_VIRTIO_CONSOLE_H */
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
new file mode 100644 (file)
index 0000000..ae469ae
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _LINUX_VIRTIO_NET_H
+#define _LINUX_VIRTIO_NET_H
+#include <linux/virtio_config.h>
+
+/* The ID for virtio_net */
+#define VIRTIO_ID_NET  1
+
+/* The bitmap of config for virtio net */
+#define VIRTIO_CONFIG_NET_F    0x40
+#define VIRTIO_NET_F_NO_CSUM   0
+#define VIRTIO_NET_F_TSO4      1
+#define VIRTIO_NET_F_UFO       2
+#define VIRTIO_NET_F_TSO4_ECN  3
+#define VIRTIO_NET_F_TSO6      4
+
+/* The config defining mac address. */
+#define VIRTIO_CONFIG_NET_MAC_F        0x41
+
+/* This is the first element of the scatter-gather list.  If you don't
+ * specify GSO or CSUM features, you can simply ignore the header. */
+struct virtio_net_hdr
+{
+#define VIRTIO_NET_HDR_F_NEEDS_CSUM    1       // Use csum_start, csum_offset
+      __u8 flags;
+#define VIRTIO_NET_HDR_GSO_NONE                0       // Not a GSO frame
+#define VIRTIO_NET_HDR_GSO_TCPV4       1       // GSO frame, IPv4 TCP (TSO)
+/* FIXME: Do we need this?  If they said they can handle ECN, do they care? */
+#define VIRTIO_NET_HDR_GSO_TCPV4_ECN   2       // GSO frame, IPv4 TCP w/ ECN
+#define VIRTIO_NET_HDR_GSO_UDP         3       // GSO frame, IPv4 UDP (UFO)
+#define VIRTIO_NET_HDR_GSO_TCPV6       4       // GSO frame, IPv6 TCP
+      __u8 gso_type;
+      __u16 gso_size;
+      __u16 csum_start;
+      __u16 csum_offset;
+};
+#endif /* _LINUX_VIRTIO_NET_H */
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
new file mode 100644 (file)
index 0000000..ac69e7b
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef _LINUX_VIRTIO_RING_H
+#define _LINUX_VIRTIO_RING_H
+/* An interface for efficient virtio implementation, currently for use by KVM
+ * and lguest, but hopefully others soon.  Do NOT change this since it will
+ * break existing servers and clients.
+ *
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Copyright Rusty Russell IBM Corporation 2007. */
+#include <linux/types.h>
+
+/* This marks a buffer as continuing via the next field. */
+#define VRING_DESC_F_NEXT      1
+/* This marks a buffer as write-only (otherwise read-only). */
+#define VRING_DESC_F_WRITE     2
+
+/* This means don't notify other side when buffer added. */
+#define VRING_USED_F_NO_NOTIFY 1
+/* This means don't interrupt guest when buffer consumed. */
+#define VRING_AVAIL_F_NO_INTERRUPT     1
+
+/* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
+struct vring_desc
+{
+       /* Address (guest-physical). */
+       __u64 addr;
+       /* Length. */
+       __u32 len;
+       /* The flags as indicated above. */
+       __u16 flags;
+       /* We chain unused descriptors via this, too */
+       __u16 next;
+};
+
+struct vring_avail
+{
+       __u16 flags;
+       __u16 idx;
+       __u16 ring[];
+};
+
+/* u32 is used here for ids for padding reasons. */
+struct vring_used_elem
+{
+       /* Index of start of used descriptor chain. */
+       __u32 id;
+       /* Total length of the descriptor chain which was used (written to) */
+       __u32 len;
+};
+
+struct vring_used
+{
+       __u16 flags;
+       __u16 idx;
+       struct vring_used_elem ring[];
+};
+
+struct vring {
+       unsigned int num;
+
+       struct vring_desc *desc;
+
+       struct vring_avail *avail;
+
+       struct vring_used *used;
+};
+
+/* The standard layout for the ring is a continuous chunk of memory which looks
+ * like this.  The used fields will be aligned to a "num+1" boundary.
+ *
+ * struct vring
+ * {
+ *     // The actual descriptors (16 bytes each)
+ *     struct vring_desc desc[num];
+ *
+ *     // A ring of available descriptor heads with free-running index.
+ *     __u16 avail_flags;
+ *     __u16 avail_idx;
+ *     __u16 available[num];
+ *
+ *     // Padding so a correctly-chosen num value will cache-align used_idx.
+ *     char pad[sizeof(struct vring_desc) - sizeof(avail_flags)];
+ *
+ *     // A ring of used descriptor heads with free-running index.
+ *     __u16 used_flags;
+ *     __u16 used_idx;
+ *     struct vring_used_elem used[num];
+ * };
+ */
+static inline void vring_init(struct vring *vr, unsigned int num, void *p)
+{
+       vr->num = num;
+       vr->desc = p;
+       vr->avail = p + num*sizeof(struct vring);
+       vr->used = p + (num+1)*(sizeof(struct vring) + sizeof(__u16));
+}
+
+static inline unsigned vring_size(unsigned int num)
+{
+       return (num + 1) * (sizeof(struct vring_desc) + sizeof(__u16))
+               + sizeof(__u32) + num * sizeof(struct vring_used_elem);
+}
+
+#ifdef __KERNEL__
+#include <linux/irqreturn.h>
+struct virtio_device;
+struct virtqueue;
+
+struct virtqueue *vring_new_virtqueue(unsigned int num,
+                                     struct virtio_device *vdev,
+                                     void *pages,
+                                     void (*notify)(struct virtqueue *vq),
+                                     bool (*callback)(struct virtqueue *vq));
+void vring_del_virtqueue(struct virtqueue *vq);
+
+irqreturn_t vring_interrupt(int irq, void *_vq);
+#endif /* __KERNEL__ */
+#endif /* _LINUX_VIRTIO_RING_H */
index cd3ff2c..88b2b5a 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/io.h>            /* for accessing devices */
 #include <linux/stringify.h>
 #include <linux/mutex.h>
+#include <linux/scatterlist.h>
 
 #include <linux/vmalloc.h>     /* for vmalloc() */
 #include <linux/mm.h>          /* for vmalloc_to_page() */
index e75d5e6..c544c6f 100644 (file)
@@ -94,7 +94,6 @@ struct video_device
        char name[32];
        int type;       /* v4l1 */
        int type2;      /* v4l2 */
-       int hardware;
        int minor;
 
        int debug;      /* Activates debug level*/
@@ -272,10 +271,6 @@ struct video_device
        int (*vidioc_s_crop)           (struct file *file, void *fh,
                                        struct v4l2_crop *a);
        /* Compression ioctls */
-       int (*vidioc_g_mpegcomp)       (struct file *file, void *fh,
-                                       struct v4l2_mpeg_compression *a);
-       int (*vidioc_s_mpegcomp)       (struct file *file, void *fh,
-                                       struct v4l2_mpeg_compression *a);
        int (*vidioc_g_jpegcomp)       (struct file *file, void *fh,
                                        struct v4l2_jpegcompression *a);
        int (*vidioc_s_jpegcomp)       (struct file *file, void *fh,
index ebfb96b..a8a9eb6 100644 (file)
@@ -200,119 +200,18 @@ enum {
 #define HCI_LM_SECURE  0x0020
 
 /* -----  HCI Commands ---- */
-/* OGF & OCF values */
-
-/* Informational Parameters */
-#define OGF_INFO_PARAM 0x04
-
-#define OCF_READ_LOCAL_VERSION 0x0001
-struct hci_rp_read_loc_version {
-       __u8     status;
-       __u8     hci_ver;
-       __le16   hci_rev;
-       __u8     lmp_ver;
-       __le16   manufacturer;
-       __le16   lmp_subver;
-} __attribute__ ((packed));
-
-#define OCF_READ_LOCAL_FEATURES        0x0003
-struct hci_rp_read_local_features {
-       __u8 status;
-       __u8 features[8];
-} __attribute__ ((packed));
-
-#define OCF_READ_BUFFER_SIZE   0x0005
-struct hci_rp_read_buffer_size {
-       __u8     status;
-       __le16   acl_mtu;
-       __u8     sco_mtu;
-       __le16   acl_max_pkt;
-       __le16   sco_max_pkt;
-} __attribute__ ((packed));
-
-#define OCF_READ_BD_ADDR       0x0009
-struct hci_rp_read_bd_addr {
-       __u8     status;
-       bdaddr_t bdaddr;
-} __attribute__ ((packed));
-
-/* Host Controller and Baseband */
-#define OGF_HOST_CTL   0x03
-#define OCF_RESET              0x0003
-#define OCF_READ_AUTH_ENABLE   0x001F
-#define OCF_WRITE_AUTH_ENABLE  0x0020
-       #define AUTH_DISABLED           0x00
-       #define AUTH_ENABLED            0x01
-
-#define OCF_READ_ENCRYPT_MODE  0x0021
-#define OCF_WRITE_ENCRYPT_MODE 0x0022
-       #define ENCRYPT_DISABLED        0x00
-       #define ENCRYPT_P2P             0x01
-       #define ENCRYPT_BOTH            0x02
-
-#define OCF_WRITE_CA_TIMEOUT   0x0016  
-#define OCF_WRITE_PG_TIMEOUT   0x0018
-
-#define OCF_WRITE_SCAN_ENABLE  0x001A
-       #define SCAN_DISABLED           0x00
-       #define SCAN_INQUIRY            0x01
-       #define SCAN_PAGE               0x02
-
-#define OCF_SET_EVENT_FLT      0x0005
-struct hci_cp_set_event_flt {
-       __u8     flt_type;
-       __u8     cond_type;
-       __u8     condition[0];
-} __attribute__ ((packed));
-
-/* Filter types */
-#define HCI_FLT_CLEAR_ALL      0x00
-#define HCI_FLT_INQ_RESULT     0x01
-#define HCI_FLT_CONN_SETUP     0x02
-
-/* CONN_SETUP Condition types */
-#define HCI_CONN_SETUP_ALLOW_ALL       0x00
-#define HCI_CONN_SETUP_ALLOW_CLASS     0x01
-#define HCI_CONN_SETUP_ALLOW_BDADDR    0x02
-
-/* CONN_SETUP Conditions */
-#define HCI_CONN_SETUP_AUTO_OFF        0x01
-#define HCI_CONN_SETUP_AUTO_ON 0x02
-
-#define OCF_READ_CLASS_OF_DEV  0x0023
-struct hci_rp_read_dev_class {
-       __u8     status;
-       __u8     dev_class[3];
-} __attribute__ ((packed));
-
-#define OCF_WRITE_CLASS_OF_DEV 0x0024
-struct hci_cp_write_dev_class {
-       __u8     dev_class[3];
-} __attribute__ ((packed));
-
-#define OCF_READ_VOICE_SETTING 0x0025
-struct hci_rp_read_voice_setting {
-       __u8     status;
-       __le16   voice_setting;
+#define HCI_OP_INQUIRY                 0x0401
+struct hci_cp_inquiry {
+       __u8     lap[3];
+       __u8     length;
+       __u8     num_rsp;
 } __attribute__ ((packed));
 
-#define OCF_WRITE_VOICE_SETTING        0x0026
-struct hci_cp_write_voice_setting {
-       __le16   voice_setting;
-} __attribute__ ((packed));
+#define HCI_OP_INQUIRY_CANCEL          0x0402
 
-#define OCF_HOST_BUFFER_SIZE   0x0033
-struct hci_cp_host_buffer_size {
-       __le16   acl_mtu;
-       __u8     sco_mtu;
-       __le16   acl_max_pkt;
-       __le16   sco_max_pkt;
-} __attribute__ ((packed));
-
-/* Link Control */
-#define OGF_LINK_CTL   0x01 
+#define HCI_OP_EXIT_PERIODIC_INQ       0x0404
 
-#define OCF_CREATE_CONN                0x0005
+#define HCI_OP_CREATE_CONN             0x0405
 struct hci_cp_create_conn {
        bdaddr_t bdaddr;
        __le16   pkt_type;
@@ -322,105 +221,138 @@ struct hci_cp_create_conn {
        __u8     role_switch;
 } __attribute__ ((packed));
 
-#define OCF_CREATE_CONN_CANCEL 0x0008
-struct hci_cp_create_conn_cancel {
-       bdaddr_t bdaddr;
-} __attribute__ ((packed));
-
-#define OCF_ACCEPT_CONN_REQ    0x0009
-struct hci_cp_accept_conn_req {
-       bdaddr_t bdaddr;
-       __u8     role;
-} __attribute__ ((packed));
-
-#define OCF_REJECT_CONN_REQ    0x000a
-struct hci_cp_reject_conn_req {
-       bdaddr_t bdaddr;
-       __u8     reason;
-} __attribute__ ((packed));
-
-#define OCF_DISCONNECT 0x0006
+#define HCI_OP_DISCONNECT              0x0406
 struct hci_cp_disconnect {
        __le16   handle;
        __u8     reason;
 } __attribute__ ((packed));
 
-#define OCF_ADD_SCO    0x0007
+#define HCI_OP_ADD_SCO                 0x0407
 struct hci_cp_add_sco {
        __le16   handle;
        __le16   pkt_type;
 } __attribute__ ((packed));
 
-#define OCF_INQUIRY            0x0001
-struct hci_cp_inquiry {
-       __u8     lap[3];
-       __u8     length;
-       __u8     num_rsp;
+#define HCI_OP_CREATE_CONN_CANCEL      0x0408
+struct hci_cp_create_conn_cancel {
+       bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define OCF_INQUIRY_CANCEL     0x0002
+#define HCI_OP_ACCEPT_CONN_REQ         0x0409
+struct hci_cp_accept_conn_req {
+       bdaddr_t bdaddr;
+       __u8     role;
+} __attribute__ ((packed));
 
-#define OCF_EXIT_PERIODIC_INQ  0x0004
+#define HCI_OP_REJECT_CONN_REQ         0x040a
+struct hci_cp_reject_conn_req {
+       bdaddr_t bdaddr;
+       __u8     reason;
+} __attribute__ ((packed));
 
-#define OCF_LINK_KEY_REPLY     0x000B
+#define HCI_OP_LINK_KEY_REPLY          0x040b
 struct hci_cp_link_key_reply {
        bdaddr_t bdaddr;
        __u8     link_key[16];
 } __attribute__ ((packed));
 
-#define OCF_LINK_KEY_NEG_REPLY 0x000C
+#define HCI_OP_LINK_KEY_NEG_REPLY      0x040c
 struct hci_cp_link_key_neg_reply {
        bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define OCF_PIN_CODE_REPLY     0x000D
+#define HCI_OP_PIN_CODE_REPLY          0x040d
 struct hci_cp_pin_code_reply {
        bdaddr_t bdaddr;
        __u8     pin_len;
        __u8     pin_code[16];
 } __attribute__ ((packed));
 
-#define OCF_PIN_CODE_NEG_REPLY 0x000E
+#define HCI_OP_PIN_CODE_NEG_REPLY      0x040e
 struct hci_cp_pin_code_neg_reply {
        bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define OCF_CHANGE_CONN_PTYPE  0x000F
+#define HCI_OP_CHANGE_CONN_PTYPE       0x040f
 struct hci_cp_change_conn_ptype {
        __le16   handle;
        __le16   pkt_type;
 } __attribute__ ((packed));
 
-#define OCF_AUTH_REQUESTED     0x0011
+#define HCI_OP_AUTH_REQUESTED          0x0411
 struct hci_cp_auth_requested {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_SET_CONN_ENCRYPT   0x0013
+#define HCI_OP_SET_CONN_ENCRYPT                0x0413
 struct hci_cp_set_conn_encrypt {
        __le16   handle;
        __u8     encrypt;
 } __attribute__ ((packed));
 
-#define OCF_CHANGE_CONN_LINK_KEY 0x0015
+#define HCI_OP_CHANGE_CONN_LINK_KEY    0x0415
 struct hci_cp_change_conn_link_key {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_READ_REMOTE_FEATURES 0x001B
+#define HCI_OP_REMOTE_NAME_REQ         0x0419
+struct hci_cp_remote_name_req {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+       __u8     pscan_mode;
+       __le16   clock_offset;
+} __attribute__ ((packed));
+
+#define HCI_OP_REMOTE_NAME_REQ_CANCEL  0x041a
+struct hci_cp_remote_name_req_cancel {
+       bdaddr_t bdaddr;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_REMOTE_FEATURES    0x041b
 struct hci_cp_read_remote_features {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_READ_REMOTE_VERSION 0x001D
+#define HCI_OP_READ_REMOTE_EXT_FEATURES        0x041c
+struct hci_cp_read_remote_ext_features {
+       __le16   handle;
+       __u8     page;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_REMOTE_VERSION     0x041d
 struct hci_cp_read_remote_version {
        __le16   handle;
 } __attribute__ ((packed));
 
-/* Link Policy */
-#define OGF_LINK_POLICY        0x02   
+#define HCI_OP_SETUP_SYNC_CONN         0x0428
+struct hci_cp_setup_sync_conn {
+       __le16   handle;
+       __le32   tx_bandwidth;
+       __le32   rx_bandwidth;
+       __le16   max_latency;
+       __le16   voice_setting;
+       __u8     retrans_effort;
+       __le16   pkt_type;
+} __attribute__ ((packed));
 
-#define OCF_SNIFF_MODE         0x0003
+#define HCI_OP_ACCEPT_SYNC_CONN_REQ    0x0429
+struct hci_cp_accept_sync_conn_req {
+       bdaddr_t bdaddr;
+       __le32   tx_bandwidth;
+       __le32   rx_bandwidth;
+       __le16   max_latency;
+       __le16   content_format;
+       __u8     retrans_effort;
+       __le16   pkt_type;
+} __attribute__ ((packed));
+
+#define HCI_OP_REJECT_SYNC_CONN_REQ    0x042a
+struct hci_cp_reject_sync_conn_req {
+       bdaddr_t bdaddr;
+       __u8     reason;
+} __attribute__ ((packed));
+
+#define HCI_OP_SNIFF_MODE              0x0803
 struct hci_cp_sniff_mode {
        __le16   handle;
        __le16   max_interval;
@@ -429,12 +361,12 @@ struct hci_cp_sniff_mode {
        __le16   timeout;
 } __attribute__ ((packed));
 
-#define OCF_EXIT_SNIFF_MODE    0x0004
+#define HCI_OP_EXIT_SNIFF_MODE         0x0804
 struct hci_cp_exit_sniff_mode {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_ROLE_DISCOVERY     0x0009
+#define HCI_OP_ROLE_DISCOVERY          0x0809
 struct hci_cp_role_discovery {
        __le16   handle;
 } __attribute__ ((packed));
@@ -444,7 +376,13 @@ struct hci_rp_role_discovery {
        __u8     role;
 } __attribute__ ((packed));
 
-#define OCF_READ_LINK_POLICY   0x000C
+#define HCI_OP_SWITCH_ROLE             0x080b
+struct hci_cp_switch_role {
+       bdaddr_t bdaddr;
+       __u8     role;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LINK_POLICY                0x080c
 struct hci_cp_read_link_policy {
        __le16   handle;
 } __attribute__ ((packed));
@@ -454,13 +392,7 @@ struct hci_rp_read_link_policy {
        __le16   policy;
 } __attribute__ ((packed));
 
-#define OCF_SWITCH_ROLE                0x000B
-struct hci_cp_switch_role {
-       bdaddr_t bdaddr;
-       __u8     role;
-} __attribute__ ((packed));
-
-#define OCF_WRITE_LINK_POLICY  0x000D
+#define HCI_OP_WRITE_LINK_POLICY       0x080d
 struct hci_cp_write_link_policy {
        __le16   handle;
        __le16   policy;
@@ -470,7 +402,7 @@ struct hci_rp_write_link_policy {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_SNIFF_SUBRATE      0x0011
+#define HCI_OP_SNIFF_SUBRATE           0x0811
 struct hci_cp_sniff_subrate {
        __le16   handle;
        __le16   max_latency;
@@ -478,59 +410,156 @@ struct hci_cp_sniff_subrate {
        __le16   min_local_timeout;
 } __attribute__ ((packed));
 
-/* Status params */
-#define OGF_STATUS_PARAM       0x05
+#define HCI_OP_SET_EVENT_MASK          0x0c01
+struct hci_cp_set_event_mask {
+       __u8     mask[8];
+} __attribute__ ((packed));
 
-/* Testing commands */
-#define OGF_TESTING_CMD                0x3E
+#define HCI_OP_RESET                   0x0c03
 
-/* Vendor specific commands */
-#define OGF_VENDOR_CMD         0x3F
+#define HCI_OP_SET_EVENT_FLT           0x0c05
+struct hci_cp_set_event_flt {
+       __u8     flt_type;
+       __u8     cond_type;
+       __u8     condition[0];
+} __attribute__ ((packed));
 
-/* ---- HCI Events ---- */
-#define HCI_EV_INQUIRY_COMPLETE        0x01
+/* Filter types */
+#define HCI_FLT_CLEAR_ALL      0x00
+#define HCI_FLT_INQ_RESULT     0x01
+#define HCI_FLT_CONN_SETUP     0x02
 
-#define HCI_EV_INQUIRY_RESULT  0x02
-struct inquiry_info {
-       bdaddr_t bdaddr;
-       __u8     pscan_rep_mode;
-       __u8     pscan_period_mode;
-       __u8     pscan_mode;
+/* CONN_SETUP Condition types */
+#define HCI_CONN_SETUP_ALLOW_ALL       0x00
+#define HCI_CONN_SETUP_ALLOW_CLASS     0x01
+#define HCI_CONN_SETUP_ALLOW_BDADDR    0x02
+
+/* CONN_SETUP Conditions */
+#define HCI_CONN_SETUP_AUTO_OFF        0x01
+#define HCI_CONN_SETUP_AUTO_ON 0x02
+
+#define HCI_OP_WRITE_LOCAL_NAME                0x0c13
+struct hci_cp_write_local_name {
+       __u8     name[248];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_NAME         0x0c14
+struct hci_rp_read_local_name {
+       __u8     status;
+       __u8     name[248];
+} __attribute__ ((packed));
+
+#define HCI_OP_WRITE_CA_TIMEOUT                0x0c16
+
+#define HCI_OP_WRITE_PG_TIMEOUT                0x0c18
+
+#define HCI_OP_WRITE_SCAN_ENABLE       0x0c1a
+       #define SCAN_DISABLED           0x00
+       #define SCAN_INQUIRY            0x01
+       #define SCAN_PAGE               0x02
+
+#define HCI_OP_READ_AUTH_ENABLE                0x0c1f
+
+#define HCI_OP_WRITE_AUTH_ENABLE       0x0c20
+       #define AUTH_DISABLED           0x00
+       #define AUTH_ENABLED            0x01
+
+#define HCI_OP_READ_ENCRYPT_MODE       0x0c21
+
+#define HCI_OP_WRITE_ENCRYPT_MODE      0x0c22
+       #define ENCRYPT_DISABLED        0x00
+       #define ENCRYPT_P2P             0x01
+       #define ENCRYPT_BOTH            0x02
+
+#define HCI_OP_READ_CLASS_OF_DEV       0x0c23
+struct hci_rp_read_class_of_dev {
+       __u8     status;
        __u8     dev_class[3];
-       __le16   clock_offset;
 } __attribute__ ((packed));
 
-#define HCI_EV_INQUIRY_RESULT_WITH_RSSI        0x22
-struct inquiry_info_with_rssi {
-       bdaddr_t bdaddr;
-       __u8     pscan_rep_mode;
-       __u8     pscan_period_mode;
+#define HCI_OP_WRITE_CLASS_OF_DEV      0x0c24
+struct hci_cp_write_class_of_dev {
        __u8     dev_class[3];
-       __le16   clock_offset;
-       __s8     rssi;
 } __attribute__ ((packed));
-struct inquiry_info_with_rssi_and_pscan_mode {
+
+#define HCI_OP_READ_VOICE_SETTING      0x0c25
+struct hci_rp_read_voice_setting {
+       __u8     status;
+       __le16   voice_setting;
+} __attribute__ ((packed));
+
+#define HCI_OP_WRITE_VOICE_SETTING     0x0c26
+struct hci_cp_write_voice_setting {
+       __le16   voice_setting;
+} __attribute__ ((packed));
+
+#define HCI_OP_HOST_BUFFER_SIZE                0x0c33
+struct hci_cp_host_buffer_size {
+       __le16   acl_mtu;
+       __u8     sco_mtu;
+       __le16   acl_max_pkt;
+       __le16   sco_max_pkt;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_VERSION      0x1001
+struct hci_rp_read_local_version {
+       __u8     status;
+       __u8     hci_ver;
+       __le16   hci_rev;
+       __u8     lmp_ver;
+       __le16   manufacturer;
+       __le16   lmp_subver;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_COMMANDS     0x1002
+struct hci_rp_read_local_commands {
+       __u8     status;
+       __u8     commands[64];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_FEATURES     0x1003
+struct hci_rp_read_local_features {
+       __u8     status;
+       __u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
+struct hci_rp_read_local_ext_features {
+       __u8     status;
+       __u8     page;
+       __u8     max_page;
+       __u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_BUFFER_SIZE                0x1005
+struct hci_rp_read_buffer_size {
+       __u8     status;
+       __le16   acl_mtu;
+       __u8     sco_mtu;
+       __le16   acl_max_pkt;
+       __le16   sco_max_pkt;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_BD_ADDR            0x1009
+struct hci_rp_read_bd_addr {
+       __u8     status;
        bdaddr_t bdaddr;
-       __u8     pscan_rep_mode;
-       __u8     pscan_period_mode;
-       __u8     pscan_mode;
-       __u8     dev_class[3];
-       __le16   clock_offset;
-       __s8     rssi;
 } __attribute__ ((packed));
 
-#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2F
-struct extended_inquiry_info {
+/* ---- HCI Events ---- */
+#define HCI_EV_INQUIRY_COMPLETE                0x01
+
+#define HCI_EV_INQUIRY_RESULT          0x02
+struct inquiry_info {
        bdaddr_t bdaddr;
        __u8     pscan_rep_mode;
        __u8     pscan_period_mode;
+       __u8     pscan_mode;
        __u8     dev_class[3];
        __le16   clock_offset;
-       __s8     rssi;
-       __u8     data[240];
 } __attribute__ ((packed));
 
-#define HCI_EV_CONN_COMPLETE   0x03
+#define HCI_EV_CONN_COMPLETE           0x03
 struct hci_ev_conn_complete {
        __u8     status;
        __le16   handle;
@@ -539,40 +568,63 @@ struct hci_ev_conn_complete {
        __u8     encr_mode;
 } __attribute__ ((packed));
 
-#define HCI_EV_CONN_REQUEST    0x04
+#define HCI_EV_CONN_REQUEST            0x04
 struct hci_ev_conn_request {
        bdaddr_t bdaddr;
        __u8     dev_class[3];
        __u8     link_type;
 } __attribute__ ((packed));
 
-#define HCI_EV_DISCONN_COMPLETE        0x05
+#define HCI_EV_DISCONN_COMPLETE                0x05
 struct hci_ev_disconn_complete {
        __u8     status;
        __le16   handle;
        __u8     reason;
 } __attribute__ ((packed));
 
-#define HCI_EV_AUTH_COMPLETE   0x06
+#define HCI_EV_AUTH_COMPLETE           0x06
 struct hci_ev_auth_complete {
        __u8     status;
        __le16   handle;
 } __attribute__ ((packed));
 
-#define HCI_EV_ENCRYPT_CHANGE  0x08
+#define HCI_EV_REMOTE_NAME             0x07
+struct hci_ev_remote_name {
+       __u8     status;
+       bdaddr_t bdaddr;
+       __u8     name[248];
+} __attribute__ ((packed));
+
+#define HCI_EV_ENCRYPT_CHANGE          0x08
 struct hci_ev_encrypt_change {
        __u8     status;
        __le16   handle;
        __u8     encrypt;
 } __attribute__ ((packed));
 
-#define HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE   0x09
-struct hci_ev_change_conn_link_key_complete {
+#define HCI_EV_CHANGE_LINK_KEY_COMPLETE        0x09
+struct hci_ev_change_link_key_complete {
+       __u8     status;
+       __le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_EV_REMOTE_FEATURES         0x0b
+struct hci_ev_remote_features {
+       __u8     status;
+       __le16   handle;
+       __u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_EV_REMOTE_VERSION          0x0c
+struct hci_ev_remote_version {
        __u8     status;
        __le16   handle;
+       __u8     lmp_ver;
+       __le16   manufacturer;
+       __le16   lmp_subver;
 } __attribute__ ((packed));
 
-#define HCI_EV_QOS_SETUP_COMPLETE      0x0D
+#define HCI_EV_QOS_SETUP_COMPLETE      0x0d
 struct hci_qos {
        __u8     service_type;
        __u32    token_rate;
@@ -586,33 +638,33 @@ struct hci_ev_qos_setup_complete {
        struct   hci_qos qos;
 } __attribute__ ((packed));
 
-#define HCI_EV_CMD_COMPLETE    0x0E
+#define HCI_EV_CMD_COMPLETE            0x0e
 struct hci_ev_cmd_complete {
        __u8     ncmd;
        __le16   opcode;
 } __attribute__ ((packed));
 
-#define HCI_EV_CMD_STATUS      0x0F
+#define HCI_EV_CMD_STATUS              0x0f
 struct hci_ev_cmd_status {
        __u8     status;
        __u8     ncmd;
        __le16   opcode;
 } __attribute__ ((packed));
 
-#define HCI_EV_NUM_COMP_PKTS   0x13
-struct hci_ev_num_comp_pkts {
-       __u8     num_hndl;
-       /* variable length part */
-} __attribute__ ((packed));
-
-#define HCI_EV_ROLE_CHANGE     0x12
+#define HCI_EV_ROLE_CHANGE             0x12
 struct hci_ev_role_change {
        __u8     status;
        bdaddr_t bdaddr;
        __u8     role;
 } __attribute__ ((packed));
 
-#define HCI_EV_MODE_CHANGE     0x14
+#define HCI_EV_NUM_COMP_PKTS           0x13
+struct hci_ev_num_comp_pkts {
+       __u8     num_hndl;
+       /* variable length part */
+} __attribute__ ((packed));
+
+#define HCI_EV_MODE_CHANGE             0x14
 struct hci_ev_mode_change {
        __u8     status;
        __le16   handle;
@@ -620,53 +672,88 @@ struct hci_ev_mode_change {
        __le16   interval;
 } __attribute__ ((packed));
 
-#define HCI_EV_PIN_CODE_REQ    0x16
+#define HCI_EV_PIN_CODE_REQ            0x16
 struct hci_ev_pin_code_req {
        bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define HCI_EV_LINK_KEY_REQ    0x17
+#define HCI_EV_LINK_KEY_REQ            0x17
 struct hci_ev_link_key_req {
        bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define HCI_EV_LINK_KEY_NOTIFY 0x18
+#define HCI_EV_LINK_KEY_NOTIFY         0x18
 struct hci_ev_link_key_notify {
        bdaddr_t bdaddr;
-       __u8     link_key[16];
-       __u8     key_type;
+       __u8     link_key[16];
+       __u8     key_type;
 } __attribute__ ((packed));
 
-#define HCI_EV_REMOTE_FEATURES 0x0B
-struct hci_ev_remote_features {
+#define HCI_EV_CLOCK_OFFSET            0x1c
+struct hci_ev_clock_offset {
        __u8     status;
        __le16   handle;
-       __u8     features[8];
+       __le16   clock_offset;
 } __attribute__ ((packed));
 
-#define HCI_EV_REMOTE_VERSION  0x0C
-struct hci_ev_remote_version {
+#define HCI_EV_PSCAN_REP_MODE          0x20
+struct hci_ev_pscan_rep_mode {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+} __attribute__ ((packed));
+
+#define HCI_EV_INQUIRY_RESULT_WITH_RSSI        0x22
+struct inquiry_info_with_rssi {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+       __u8     pscan_period_mode;
+       __u8     dev_class[3];
+       __le16   clock_offset;
+       __s8     rssi;
+} __attribute__ ((packed));
+struct inquiry_info_with_rssi_and_pscan_mode {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+       __u8     pscan_period_mode;
+       __u8     pscan_mode;
+       __u8     dev_class[3];
+       __le16   clock_offset;
+       __s8     rssi;
+} __attribute__ ((packed));
+
+#define HCI_EV_REMOTE_EXT_FEATURES     0x23
+struct hci_ev_remote_ext_features {
        __u8     status;
        __le16   handle;
-       __u8     lmp_ver;
-       __le16   manufacturer;
-       __le16   lmp_subver;
+       __u8     page;
+       __u8     max_page;
+       __u8     features[8];
 } __attribute__ ((packed));
 
-#define HCI_EV_CLOCK_OFFSET    0x01C
-struct hci_ev_clock_offset {
+#define HCI_EV_SYNC_CONN_COMPLETE      0x2c
+struct hci_ev_sync_conn_complete {
        __u8     status;
        __le16   handle;
-       __le16   clock_offset;
+       bdaddr_t bdaddr;
+       __u8     link_type;
+       __u8     tx_interval;
+       __u8     retrans_window;
+       __le16   rx_pkt_len;
+       __le16   tx_pkt_len;
+       __u8     air_mode;
 } __attribute__ ((packed));
 
-#define HCI_EV_PSCAN_REP_MODE  0x20
-struct hci_ev_pscan_rep_mode {
-       bdaddr_t bdaddr;
-       __u8     pscan_rep_mode;
+#define HCI_EV_SYNC_CONN_CHANGED       0x2d
+struct hci_ev_sync_conn_changed {
+       __u8     status;
+       __le16   handle;
+       __u8     tx_interval;
+       __u8     retrans_window;
+       __le16   rx_pkt_len;
+       __le16   tx_pkt_len;
 } __attribute__ ((packed));
 
-#define HCI_EV_SNIFF_SUBRATE   0x2E
+#define HCI_EV_SNIFF_SUBRATE           0x2e
 struct hci_ev_sniff_subrate {
        __u8     status;
        __le16   handle;
@@ -676,14 +763,25 @@ struct hci_ev_sniff_subrate {
        __le16   max_local_timeout;
 } __attribute__ ((packed));
 
+#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f
+struct extended_inquiry_info {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+       __u8     pscan_period_mode;
+       __u8     dev_class[3];
+       __le16   clock_offset;
+       __s8     rssi;
+       __u8     data[240];
+} __attribute__ ((packed));
+
 /* Internal events generated by Bluetooth stack */
-#define HCI_EV_STACK_INTERNAL  0xFD
+#define HCI_EV_STACK_INTERNAL  0xfd
 struct hci_ev_stack_internal {
        __u16    type;
        __u8     data[0];
 } __attribute__ ((packed));
 
-#define HCI_EV_SI_DEVICE       0x01
+#define HCI_EV_SI_DEVICE       0x01
 struct hci_ev_si_device {
        __u16    event;
        __u16    dev_id;
@@ -704,40 +802,40 @@ struct hci_ev_si_security {
 #define HCI_SCO_HDR_SIZE     3
 
 struct hci_command_hdr {
-       __le16  opcode;         /* OCF & OGF */
+       __le16  opcode;         /* OCF & OGF */
        __u8    plen;
 } __attribute__ ((packed));
 
 struct hci_event_hdr {
-       __u8    evt;
-       __u8    plen;
+       __u8    evt;
+       __u8    plen;
 } __attribute__ ((packed));
 
 struct hci_acl_hdr {
-       __le16  handle;         /* Handle & Flags(PB, BC) */
-       __le16  dlen;
+       __le16  handle;         /* Handle & Flags(PB, BC) */
+       __le16  dlen;
 } __attribute__ ((packed));
 
 struct hci_sco_hdr {
-       __le16  handle;
-       __u8    dlen;
+       __le16  handle;
+       __u8    dlen;
 } __attribute__ ((packed));
 
 #ifdef __KERNEL__
 #include <linux/skbuff.h>
 static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
 {
-       return (struct hci_event_hdr *)skb->data;
+       return (struct hci_event_hdr *) skb->data;
 }
 
 static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb)
 {
-       return (struct hci_acl_hdr *)skb->data;
+       return (struct hci_acl_hdr *) skb->data;
 }
 
 static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
 {
-       return (struct hci_sco_hdr *)skb->data;
+       return (struct hci_sco_hdr *) skb->data;
 }
 #endif
 
@@ -771,13 +869,13 @@ struct sockaddr_hci {
 struct hci_filter {
        unsigned long type_mask;
        unsigned long event_mask[2];
-       __le16   opcode;
+       __le16 opcode;
 };
 
 struct hci_ufilter {
-       __u32   type_mask;
-       __u32   event_mask[2];
-       __le16   opcode;
+       __u32  type_mask;
+       __u32  event_mask[2];
+       __le16 opcode;
 };
 
 #define HCI_FLT_TYPE_BITS      31
@@ -825,15 +923,15 @@ struct hci_dev_info {
 struct hci_conn_info {
        __u16    handle;
        bdaddr_t bdaddr;
-       __u8     type;
-       __u8     out;
-       __u16    state;
-       __u32    link_mode;
+       __u8     type;
+       __u8     out;
+       __u16    state;
+       __u32    link_mode;
 };
 
 struct hci_dev_req {
-       __u16 dev_id;
-       __u32 dev_opt;
+       __u16  dev_id;
+       __u32  dev_opt;
 };
 
 struct hci_dev_list_req {
index 8f67c8a..ea13baa 100644 (file)
@@ -71,7 +71,10 @@ struct hci_dev {
        __u16           id;
        __u8            type;
        bdaddr_t        bdaddr;
+       __u8            dev_name[248];
+       __u8            dev_class[3];
        __u8            features[8];
+       __u8            commands[64];
        __u8            hci_ver;
        __u16           hci_rev;
        __u16           manufacturer;
@@ -310,10 +313,12 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
 void hci_acl_connect(struct hci_conn *conn);
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
 void hci_add_sco(struct hci_conn *conn, __u16 handle);
+void hci_setup_sync(struct hci_conn *conn, __u16 handle);
 
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
-int    hci_conn_del(struct hci_conn *conn);
-void   hci_conn_hash_flush(struct hci_dev *hdev);
+int hci_conn_del(struct hci_conn *conn);
+void hci_conn_hash_flush(struct hci_dev *hdev);
+void hci_conn_check_pending(struct hci_dev *hdev);
 
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
 int hci_conn_auth(struct hci_conn *conn);
@@ -617,11 +622,11 @@ int hci_unregister_cb(struct hci_cb *hcb);
 int hci_register_notifier(struct notifier_block *nb);
 int hci_unregister_notifier(struct notifier_block *nb);
 
-int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
 int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
 int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
 
 void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
 
index 70e70f5..73e115b 100644 (file)
@@ -29,7 +29,8 @@
 #define L2CAP_DEFAULT_MTU      672
 #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
 
-#define L2CAP_CONN_TIMEOUT     (HZ * 40)
+#define L2CAP_CONN_TIMEOUT     (40000) /* 40 seconds */
+#define L2CAP_INFO_TIMEOUT     (4000)  /*  4 seconds */
 
 /* L2CAP socket address */
 struct sockaddr_l2 {
@@ -148,6 +149,19 @@ struct l2cap_conf_opt {
 
 #define L2CAP_CONF_MAX_SIZE    22
 
+struct l2cap_conf_rfc {
+       __u8       mode;
+       __u8       txwin_size;
+       __u8       max_transmit;
+       __le16     retrans_timeout;
+       __le16     monitor_timeout;
+       __le16     max_pdu_size;
+} __attribute__ ((packed));
+
+#define L2CAP_MODE_BASIC       0x00
+#define L2CAP_MODE_RETRANS     0x01
+#define L2CAP_MODE_FLOWCTL     0x02
+
 struct l2cap_disconn_req {
        __le16     dcid;
        __le16     scid;
@@ -160,7 +174,6 @@ struct l2cap_disconn_rsp {
 
 struct l2cap_info_req {
        __le16      type;
-       __u8        data[0];
 } __attribute__ ((packed));
 
 struct l2cap_info_rsp {
@@ -192,6 +205,13 @@ struct l2cap_conn {
 
        unsigned int    mtu;
 
+       __u32           feat_mask;
+
+       __u8            info_state;
+       __u8            info_ident;
+
+       struct timer_list info_timer;
+
        spinlock_t      lock;
 
        struct sk_buff *rx_skb;
@@ -202,6 +222,9 @@ struct l2cap_conn {
        struct l2cap_chan_list chan_list;
 };
 
+#define L2CAP_INFO_CL_MTU_REQ_SENT     0x01
+#define L2CAP_INFO_FEAT_MASK_REQ_SENT  0x02
+
 /* ----- L2CAP channel and socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
@@ -221,7 +244,6 @@ struct l2cap_pinfo {
        __u8            conf_len;
        __u8            conf_state;
        __u8            conf_retry;
-       __u16           conf_mtu;
 
        __u8            ident;
 
@@ -232,10 +254,11 @@ struct l2cap_pinfo {
        struct sock             *prev_c;
 };
 
-#define L2CAP_CONF_REQ_SENT    0x01
-#define L2CAP_CONF_INPUT_DONE  0x02
-#define L2CAP_CONF_OUTPUT_DONE 0x04
-#define L2CAP_CONF_MAX_RETRIES 2
+#define L2CAP_CONF_REQ_SENT    0x01
+#define L2CAP_CONF_INPUT_DONE  0x02
+#define L2CAP_CONF_OUTPUT_DONE 0x04
+
+#define L2CAP_CONF_MAX_RETRIES 2
 
 void l2cap_load(void);
 
index 8d4a8dd..a2be8ad 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by alsa/ksync script.  */
 #define CONFIG_SND_VERSION "1.0.15"
-#define CONFIG_SND_DATE " (Tue Oct 16 14:57:44 2007 UTC)"
+#define CONFIG_SND_DATE " (Tue Oct 23 06:09:18 2007 UTC)"
index 53a6c73..0e406f7 100644 (file)
@@ -1 +1,2 @@
 unifdef-y += sisfb.h uvesafb.h
+unifdef-y += edid.h
index f6a42d6..928c342 100644 (file)
@@ -1,17 +1,16 @@
 #ifndef __linux_video_edid_h__
 #define __linux_video_edid_h__
 
-#ifdef __KERNEL__
-
+#if !defined(__KERNEL__) || defined(CONFIG_X86)
 
-#ifdef CONFIG_X86
 struct edid_info {
        unsigned char dummy[128];
 };
 
+#ifdef __KERNEL__
 extern struct edid_info edid_info;
-#endif /* CONFIG_X86 */
-
 #endif /* __KERNEL__ */
 
+#endif
+
 #endif /* __linux_video_edid_h__ */
index 541382d..b7dffa8 100644 (file)
@@ -234,6 +234,10 @@ config AUDITSYSCALL
          such as SELinux.  To use audit's filesystem watch feature, please
          ensure that INOTIFY is configured.
 
+config AUDIT_TREE
+       def_bool y
+       depends on AUDITSYSCALL && INOTIFY
+
 config IKCONFIG
        tristate "Kernel .config support"
        ---help---
index c0b26dc..bfa274b 100644 (file)
@@ -676,7 +676,7 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
 
        if (oflag & O_CREAT) {
                if (dentry->d_inode) {  /* entry already exists */
-                       audit_inode(name, dentry->d_inode);
+                       audit_inode(name, dentry);
                        error = -EEXIST;
                        if (oflag & O_EXCL)
                                goto out;
@@ -689,7 +689,7 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
                error = -ENOENT;
                if (!dentry->d_inode)
                        goto out;
-               audit_inode(name, dentry->d_inode);
+               audit_inode(name, dentry);
                filp = do_open(dentry, oflag);
        }
 
@@ -837,7 +837,7 @@ asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
        if (unlikely(filp->f_op != &mqueue_file_operations))
                goto out_fput;
        info = MQUEUE_I(inode);
-       audit_inode(NULL, inode);
+       audit_inode(NULL, filp->f_path.dentry);
 
        if (unlikely(!(filp->f_mode & FMODE_WRITE)))
                goto out_fput;
@@ -921,7 +921,7 @@ asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
        if (unlikely(filp->f_op != &mqueue_file_operations))
                goto out_fput;
        info = MQUEUE_I(inode);
-       audit_inode(NULL, inode);
+       audit_inode(NULL, filp->f_path.dentry);
 
        if (unlikely(!(filp->f_mode & FMODE_READ)))
                goto out_fput;
index 79f017e..f60afe7 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
 obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
+obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
 obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
index 6977ea5..f93c271 100644 (file)
@@ -468,6 +468,21 @@ int audit_send_list(void *_dest)
        return 0;
 }
 
+#ifdef CONFIG_AUDIT_TREE
+static int prune_tree_thread(void *unused)
+{
+       mutex_lock(&audit_cmd_mutex);
+       audit_prune_trees();
+       mutex_unlock(&audit_cmd_mutex);
+       return 0;
+}
+
+void audit_schedule_prune(void)
+{
+       kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
+}
+#endif
+
 struct sk_buff *audit_make_reply(int pid, int seq, int type, int done,
                                 int multi, void *payload, int size)
 {
@@ -540,6 +555,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
        case AUDIT_SIGNAL_INFO:
        case AUDIT_TTY_GET:
        case AUDIT_TTY_SET:
+       case AUDIT_TRIM:
+       case AUDIT_MAKE_EQUIV:
                if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
                        err = -EPERM;
                break;
@@ -756,6 +773,76 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                           uid, seq, data, nlmsg_len(nlh),
                                           loginuid, sid);
                break;
+       case AUDIT_TRIM:
+               audit_trim_trees();
+               ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+               if (!ab)
+                       break;
+               audit_log_format(ab, "auid=%u", loginuid);
+               if (sid) {
+                       u32 len;
+                       ctx = NULL;
+                       if (selinux_sid_to_string(sid, &ctx, &len))
+                               audit_log_format(ab, " ssid=%u", sid);
+                       else
+                               audit_log_format(ab, " subj=%s", ctx);
+                       kfree(ctx);
+               }
+               audit_log_format(ab, " op=trim res=1");
+               audit_log_end(ab);
+               break;
+       case AUDIT_MAKE_EQUIV: {
+               void *bufp = data;
+               u32 sizes[2];
+               size_t len = nlmsg_len(nlh);
+               char *old, *new;
+
+               err = -EINVAL;
+               if (len < 2 * sizeof(u32))
+                       break;
+               memcpy(sizes, bufp, 2 * sizeof(u32));
+               bufp += 2 * sizeof(u32);
+               len -= 2 * sizeof(u32);
+               old = audit_unpack_string(&bufp, &len, sizes[0]);
+               if (IS_ERR(old)) {
+                       err = PTR_ERR(old);
+                       break;
+               }
+               new = audit_unpack_string(&bufp, &len, sizes[1]);
+               if (IS_ERR(new)) {
+                       err = PTR_ERR(new);
+                       kfree(old);
+                       break;
+               }
+               /* OK, here comes... */
+               err = audit_tag_tree(old, new);
+
+               ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+               if (!ab) {
+                       kfree(old);
+                       kfree(new);
+                       break;
+               }
+               audit_log_format(ab, "auid=%u", loginuid);
+               if (sid) {
+                       u32 len;
+                       ctx = NULL;
+                       if (selinux_sid_to_string(sid, &ctx, &len))
+                               audit_log_format(ab, " ssid=%u", sid);
+                       else
+                               audit_log_format(ab, " subj=%s", ctx);
+                       kfree(ctx);
+               }
+               audit_log_format(ab, " op=make_equiv old=");
+               audit_log_untrustedstring(ab, old);
+               audit_log_format(ab, " new=");
+               audit_log_untrustedstring(ab, new);
+               audit_log_format(ab, " res=%d", !err);
+               audit_log_end(ab);
+               kfree(old);
+               kfree(new);
+               break;
+       }
        case AUDIT_SIGNAL_INFO:
                err = selinux_sid_to_string(audit_sig_sid, &ctx, &len);
                if (err)
index 9587743..2554bd5 100644 (file)
@@ -73,6 +73,9 @@ struct audit_field {
        struct selinux_audit_rule       *se_rule;
 };
 
+struct audit_tree;
+struct audit_chunk;
+
 struct audit_krule {
        int                     vers_ops;
        u32                     flags;
@@ -86,7 +89,8 @@ struct audit_krule {
        struct audit_field      *arch_f; /* quick access to arch field */
        struct audit_field      *inode_f; /* quick access to an inode field */
        struct audit_watch      *watch; /* associated watch */
-       struct list_head        rlist;  /* entry in audit_watch.rules list */
+       struct audit_tree       *tree;  /* associated watched tree */
+       struct list_head        rlist;  /* entry in audit_{watch,tree}.rules list */
 };
 
 struct audit_entry {
@@ -130,6 +134,34 @@ extern void audit_handle_ievent(struct inotify_watch *, u32, u32, u32,
                                const char *, struct inode *);
 extern int selinux_audit_rule_update(void);
 
+extern struct mutex audit_filter_mutex;
+extern void audit_free_rule_rcu(struct rcu_head *);
+
+#ifdef CONFIG_AUDIT_TREE
+extern struct audit_chunk *audit_tree_lookup(const struct inode *);
+extern void audit_put_chunk(struct audit_chunk *);
+extern int audit_tree_match(struct audit_chunk *, struct audit_tree *);
+extern int audit_make_tree(struct audit_krule *, char *, u32);
+extern int audit_add_tree_rule(struct audit_krule *);
+extern int audit_remove_tree_rule(struct audit_krule *);
+extern void audit_trim_trees(void);
+extern int audit_tag_tree(char *old, char *new);
+extern void audit_schedule_prune(void);
+extern void audit_prune_trees(void);
+extern const char *audit_tree_path(struct audit_tree *);
+extern void audit_put_tree(struct audit_tree *);
+#else
+#define audit_remove_tree_rule(rule) BUG()
+#define audit_add_tree_rule(rule) -EINVAL
+#define audit_make_tree(rule, str, op) -EINVAL
+#define audit_trim_trees() (void)0
+#define audit_put_tree(tree) (void)0
+#define audit_tag_tree(old, new) -EINVAL
+#define audit_tree_path(rule) ""       /* never called */
+#endif
+
+extern char *audit_unpack_string(void **, size_t *, size_t);
+
 #ifdef CONFIG_AUDITSYSCALL
 extern int __audit_signal_info(int sig, struct task_struct *t);
 static inline int audit_signal_info(int sig, struct task_struct *t)
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
new file mode 100644 (file)
index 0000000..f4fcf58
--- /dev/null
@@ -0,0 +1,903 @@
+#include "audit.h"
+#include <linux/inotify.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+
+struct audit_tree;
+struct audit_chunk;
+
+struct audit_tree {
+       atomic_t count;
+       int goner;
+       struct audit_chunk *root;
+       struct list_head chunks;
+       struct list_head rules;
+       struct list_head list;
+       struct list_head same_root;
+       struct rcu_head head;
+       char pathname[];
+};
+
+struct audit_chunk {
+       struct list_head hash;
+       struct inotify_watch watch;
+       struct list_head trees;         /* with root here */
+       int dead;
+       int count;
+       struct rcu_head head;
+       struct node {
+               struct list_head list;
+               struct audit_tree *owner;
+               unsigned index;         /* index; upper bit indicates 'will prune' */
+       } owners[];
+};
+
+static LIST_HEAD(tree_list);
+static LIST_HEAD(prune_list);
+
+/*
+ * One struct chunk is attached to each inode of interest.
+ * We replace struct chunk on tagging/untagging.
+ * Rules have pointer to struct audit_tree.
+ * Rules have struct list_head rlist forming a list of rules over
+ * the same tree.
+ * References to struct chunk are collected at audit_inode{,_child}()
+ * time and used in AUDIT_TREE rule matching.
+ * These references are dropped at the same time we are calling
+ * audit_free_names(), etc.
+ *
+ * Cyclic lists galore:
+ * tree.chunks anchors chunk.owners[].list                     hash_lock
+ * tree.rules anchors rule.rlist                               audit_filter_mutex
+ * chunk.trees anchors tree.same_root                          hash_lock
+ * chunk.hash is a hash with middle bits of watch.inode as
+ * a hash function.                                            RCU, hash_lock
+ *
+ * tree is refcounted; one reference for "some rules on rules_list refer to
+ * it", one for each chunk with pointer to it.
+ *
+ * chunk is refcounted by embedded inotify_watch.
+ *
+ * node.index allows to get from node.list to containing chunk.
+ * MSB of that sucker is stolen to mark taggings that we might have to
+ * revert - several operations have very unpleasant cleanup logics and
+ * that makes a difference.  Some.
+ */
+
+static struct inotify_handle *rtree_ih;
+
+static struct audit_tree *alloc_tree(const char *s)
+{
+       struct audit_tree *tree;
+
+       tree = kmalloc(sizeof(struct audit_tree) + strlen(s) + 1, GFP_KERNEL);
+       if (tree) {
+               atomic_set(&tree->count, 1);
+               tree->goner = 0;
+               INIT_LIST_HEAD(&tree->chunks);
+               INIT_LIST_HEAD(&tree->rules);
+               INIT_LIST_HEAD(&tree->list);
+               INIT_LIST_HEAD(&tree->same_root);
+               tree->root = NULL;
+               strcpy(tree->pathname, s);
+       }
+       return tree;
+}
+
+static inline void get_tree(struct audit_tree *tree)
+{
+       atomic_inc(&tree->count);
+}
+
+static void __put_tree(struct rcu_head *rcu)
+{
+       struct audit_tree *tree = container_of(rcu, struct audit_tree, head);
+       kfree(tree);
+}
+
+static inline void put_tree(struct audit_tree *tree)
+{
+       if (atomic_dec_and_test(&tree->count))
+               call_rcu(&tree->head, __put_tree);
+}
+
+/* to avoid bringing the entire thing in audit.h */
+const char *audit_tree_path(struct audit_tree *tree)
+{
+       return tree->pathname;
+}
+
+static struct audit_chunk *alloc_chunk(int count)
+{
+       struct audit_chunk *chunk;
+       size_t size;
+       int i;
+
+       size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
+       chunk = kzalloc(size, GFP_KERNEL);
+       if (!chunk)
+               return NULL;
+
+       INIT_LIST_HEAD(&chunk->hash);
+       INIT_LIST_HEAD(&chunk->trees);
+       chunk->count = count;
+       for (i = 0; i < count; i++) {
+               INIT_LIST_HEAD(&chunk->owners[i].list);
+               chunk->owners[i].index = i;
+       }
+       inotify_init_watch(&chunk->watch);
+       return chunk;
+}
+
+static void __free_chunk(struct rcu_head *rcu)
+{
+       struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
+       int i;
+
+       for (i = 0; i < chunk->count; i++) {
+               if (chunk->owners[i].owner)
+                       put_tree(chunk->owners[i].owner);
+       }
+       kfree(chunk);
+}
+
+static inline void free_chunk(struct audit_chunk *chunk)
+{
+       call_rcu(&chunk->head, __free_chunk);
+}
+
+void audit_put_chunk(struct audit_chunk *chunk)
+{
+       put_inotify_watch(&chunk->watch);
+}
+
+enum {HASH_SIZE = 128};
+static struct list_head chunk_hash_heads[HASH_SIZE];
+static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock);
+
+static inline struct list_head *chunk_hash(const struct inode *inode)
+{
+       unsigned long n = (unsigned long)inode / L1_CACHE_BYTES;
+       return chunk_hash_heads + n % HASH_SIZE;
+}
+
+/* hash_lock is held by caller */
+static void insert_hash(struct audit_chunk *chunk)
+{
+       struct list_head *list = chunk_hash(chunk->watch.inode);
+       list_add_rcu(&chunk->hash, list);
+}
+
+/* called under rcu_read_lock */
+struct audit_chunk *audit_tree_lookup(const struct inode *inode)
+{
+       struct list_head *list = chunk_hash(inode);
+       struct list_head *pos;
+
+       list_for_each_rcu(pos, list) {
+               struct audit_chunk *p = container_of(pos, struct audit_chunk, hash);
+               if (p->watch.inode == inode) {
+                       get_inotify_watch(&p->watch);
+                       return p;
+               }
+       }
+       return NULL;
+}
+
+int audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
+{
+       int n;
+       for (n = 0; n < chunk->count; n++)
+               if (chunk->owners[n].owner == tree)
+                       return 1;
+       return 0;
+}
+
+/* tagging and untagging inodes with trees */
+
+static void untag_chunk(struct audit_chunk *chunk, struct node *p)
+{
+       struct audit_chunk *new;
+       struct audit_tree *owner;
+       int size = chunk->count - 1;
+       int i, j;
+
+       mutex_lock(&chunk->watch.inode->inotify_mutex);
+       if (chunk->dead) {
+               mutex_unlock(&chunk->watch.inode->inotify_mutex);
+               return;
+       }
+
+       owner = p->owner;
+
+       if (!size) {
+               chunk->dead = 1;
+               spin_lock(&hash_lock);
+               list_del_init(&chunk->trees);
+               if (owner->root == chunk)
+                       owner->root = NULL;
+               list_del_init(&p->list);
+               list_del_rcu(&chunk->hash);
+               spin_unlock(&hash_lock);
+               inotify_evict_watch(&chunk->watch);
+               mutex_unlock(&chunk->watch.inode->inotify_mutex);
+               put_inotify_watch(&chunk->watch);
+               return;
+       }
+
+       new = alloc_chunk(size);
+       if (!new)
+               goto Fallback;
+       if (inotify_clone_watch(&chunk->watch, &new->watch) < 0) {
+               free_chunk(new);
+               goto Fallback;
+       }
+
+       chunk->dead = 1;
+       spin_lock(&hash_lock);
+       list_replace_init(&chunk->trees, &new->trees);
+       if (owner->root == chunk) {
+               list_del_init(&owner->same_root);
+               owner->root = NULL;
+       }
+
+       for (i = j = 0; i < size; i++, j++) {
+               struct audit_tree *s;
+               if (&chunk->owners[j] == p) {
+                       list_del_init(&p->list);
+                       i--;
+                       continue;
+               }
+               s = chunk->owners[j].owner;
+               new->owners[i].owner = s;
+               new->owners[i].index = chunk->owners[j].index - j + i;
+               if (!s) /* result of earlier fallback */
+                       continue;
+               get_tree(s);
+               list_replace_init(&chunk->owners[i].list, &new->owners[j].list);
+       }
+
+       list_replace_rcu(&chunk->hash, &new->hash);
+       list_for_each_entry(owner, &new->trees, same_root)
+               owner->root = new;
+       spin_unlock(&hash_lock);
+       inotify_evict_watch(&chunk->watch);
+       mutex_unlock(&chunk->watch.inode->inotify_mutex);
+       put_inotify_watch(&chunk->watch);
+       return;
+
+Fallback:
+       // do the best we can
+       spin_lock(&hash_lock);
+       if (owner->root == chunk) {
+               list_del_init(&owner->same_root);
+               owner->root = NULL;
+       }
+       list_del_init(&p->list);
+       p->owner = NULL;
+       put_tree(owner);
+       spin_unlock(&hash_lock);
+       mutex_unlock(&chunk->watch.inode->inotify_mutex);
+}
+
+static int create_chunk(struct inode *inode, struct audit_tree *tree)
+{
+       struct audit_chunk *chunk = alloc_chunk(1);
+       if (!chunk)
+               return -ENOMEM;
+
+       if (inotify_add_watch(rtree_ih, &chunk->watch, inode, IN_IGNORED | IN_DELETE_SELF) < 0) {
+               free_chunk(chunk);
+               return -ENOSPC;
+       }
+
+       mutex_lock(&inode->inotify_mutex);
+       spin_lock(&hash_lock);
+       if (tree->goner) {
+               spin_unlock(&hash_lock);
+               chunk->dead = 1;
+               inotify_evict_watch(&chunk->watch);
+               mutex_unlock(&inode->inotify_mutex);
+               put_inotify_watch(&chunk->watch);
+               return 0;
+       }
+       chunk->owners[0].index = (1U << 31);
+       chunk->owners[0].owner = tree;
+       get_tree(tree);
+       list_add(&chunk->owners[0].list, &tree->chunks);
+       if (!tree->root) {
+               tree->root = chunk;
+               list_add(&tree->same_root, &chunk->trees);
+       }
+       insert_hash(chunk);
+       spin_unlock(&hash_lock);
+       mutex_unlock(&inode->inotify_mutex);
+       return 0;
+}
+
+/* the first tagged inode becomes root of tree */
+static int tag_chunk(struct inode *inode, struct audit_tree *tree)
+{
+       struct inotify_watch *watch;
+       struct audit_tree *owner;
+       struct audit_chunk *chunk, *old;
+       struct node *p;
+       int n;
+
+       if (inotify_find_watch(rtree_ih, inode, &watch) < 0)
+               return create_chunk(inode, tree);
+
+       old = container_of(watch, struct audit_chunk, watch);
+
+       /* are we already there? */
+       spin_lock(&hash_lock);
+       for (n = 0; n < old->count; n++) {
+               if (old->owners[n].owner == tree) {
+                       spin_unlock(&hash_lock);
+                       put_inotify_watch(watch);
+                       return 0;
+               }
+       }
+       spin_unlock(&hash_lock);
+
+       chunk = alloc_chunk(old->count + 1);
+       if (!chunk)
+               return -ENOMEM;
+
+       mutex_lock(&inode->inotify_mutex);
+       if (inotify_clone_watch(&old->watch, &chunk->watch) < 0) {
+               mutex_unlock(&inode->inotify_mutex);
+               free_chunk(chunk);
+               return -ENOSPC;
+       }
+       spin_lock(&hash_lock);
+       if (tree->goner) {
+               spin_unlock(&hash_lock);
+               chunk->dead = 1;
+               inotify_evict_watch(&chunk->watch);
+               mutex_unlock(&inode->inotify_mutex);
+               put_inotify_watch(&chunk->watch);
+               return 0;
+       }
+       list_replace_init(&old->trees, &chunk->trees);
+       for (n = 0, p = chunk->owners; n < old->count; n++, p++) {
+               struct audit_tree *s = old->owners[n].owner;
+               p->owner = s;
+               p->index = old->owners[n].index;
+               if (!s) /* result of fallback in untag */
+                       continue;
+               get_tree(s);
+               list_replace_init(&old->owners[n].list, &p->list);
+       }
+       p->index = (chunk->count - 1) | (1U<<31);
+       p->owner = tree;
+       get_tree(tree);
+       list_add(&p->list, &tree->chunks);
+       list_replace_rcu(&old->hash, &chunk->hash);
+       list_for_each_entry(owner, &chunk->trees, same_root)
+               owner->root = chunk;
+       old->dead = 1;
+       if (!tree->root) {
+               tree->root = chunk;
+               list_add(&tree->same_root, &chunk->trees);
+       }
+       spin_unlock(&hash_lock);
+       inotify_evict_watch(&old->watch);
+       mutex_unlock(&inode->inotify_mutex);
+       put_inotify_watch(&old->watch);
+       return 0;
+}
+
+static struct audit_chunk *find_chunk(struct node *p)
+{
+       int index = p->index & ~(1U<<31);
+       p -= index;
+       return container_of(p, struct audit_chunk, owners[0]);
+}
+
+static void kill_rules(struct audit_tree *tree)
+{
+       struct audit_krule *rule, *next;
+       struct audit_entry *entry;
+       struct audit_buffer *ab;
+
+       list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
+               entry = container_of(rule, struct audit_entry, rule);
+
+               list_del_init(&rule->rlist);
+               if (rule->tree) {
+                       /* not a half-baked one */
+                       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+                       audit_log_format(ab, "op=remove rule dir=");
+                       audit_log_untrustedstring(ab, rule->tree->pathname);
+                       if (rule->filterkey) {
+                               audit_log_format(ab, " key=");
+                               audit_log_untrustedstring(ab, rule->filterkey);
+                       } else
+                               audit_log_format(ab, " key=(null)");
+                       audit_log_format(ab, " list=%d res=1", rule->listnr);
+                       audit_log_end(ab);
+                       rule->tree = NULL;
+                       list_del_rcu(&entry->list);
+                       call_rcu(&entry->rcu, audit_free_rule_rcu);
+               }
+       }
+}
+
+/*
+ * finish killing struct audit_tree
+ */
+static void prune_one(struct audit_tree *victim)
+{
+       spin_lock(&hash_lock);
+       while (!list_empty(&victim->chunks)) {
+               struct node *p;
+               struct audit_chunk *chunk;
+
+               p = list_entry(victim->chunks.next, struct node, list);
+               chunk = find_chunk(p);
+               get_inotify_watch(&chunk->watch);
+               spin_unlock(&hash_lock);
+
+               untag_chunk(chunk, p);
+
+               put_inotify_watch(&chunk->watch);
+               spin_lock(&hash_lock);
+       }
+       spin_unlock(&hash_lock);
+       put_tree(victim);
+}
+
+/* trim the uncommitted chunks from tree */
+
+static void trim_marked(struct audit_tree *tree)
+{
+       struct list_head *p, *q;
+       spin_lock(&hash_lock);
+       if (tree->goner) {
+               spin_unlock(&hash_lock);
+               return;
+       }
+       /* reorder */
+       for (p = tree->chunks.next; p != &tree->chunks; p = q) {
+               struct node *node = list_entry(p, struct node, list);
+               q = p->next;
+               if (node->index & (1U<<31)) {
+                       list_del_init(p);
+                       list_add(p, &tree->chunks);
+               }
+       }
+
+       while (!list_empty(&tree->chunks)) {
+               struct node *node;
+               struct audit_chunk *chunk;
+
+               node = list_entry(tree->chunks.next, struct node, list);
+
+               /* have we run out of marked? */
+               if (!(node->index & (1U<<31)))
+                       break;
+
+               chunk = find_chunk(node);
+               get_inotify_watch(&chunk->watch);
+               spin_unlock(&hash_lock);
+
+               untag_chunk(chunk, node);
+
+               put_inotify_watch(&chunk->watch);
+               spin_lock(&hash_lock);
+       }
+       if (!tree->root && !tree->goner) {
+               tree->goner = 1;
+               spin_unlock(&hash_lock);
+               mutex_lock(&audit_filter_mutex);
+               kill_rules(tree);
+               list_del_init(&tree->list);
+               mutex_unlock(&audit_filter_mutex);
+               prune_one(tree);
+       } else {
+               spin_unlock(&hash_lock);
+       }
+}
+
+/* called with audit_filter_mutex */
+int audit_remove_tree_rule(struct audit_krule *rule)
+{
+       struct audit_tree *tree;
+       tree = rule->tree;
+       if (tree) {
+               spin_lock(&hash_lock);
+               list_del_init(&rule->rlist);
+               if (list_empty(&tree->rules) && !tree->goner) {
+                       tree->root = NULL;
+                       list_del_init(&tree->same_root);
+                       tree->goner = 1;
+                       list_move(&tree->list, &prune_list);
+                       rule->tree = NULL;
+                       spin_unlock(&hash_lock);
+                       audit_schedule_prune();
+                       return 1;
+               }
+               rule->tree = NULL;
+               spin_unlock(&hash_lock);
+               return 1;
+       }
+       return 0;
+}
+
+void audit_trim_trees(void)
+{
+       struct list_head cursor;
+
+       mutex_lock(&audit_filter_mutex);
+       list_add(&cursor, &tree_list);
+       while (cursor.next != &tree_list) {
+               struct audit_tree *tree;
+               struct nameidata nd;
+               struct vfsmount *root_mnt;
+               struct node *node;
+               struct list_head list;
+               int err;
+
+               tree = container_of(cursor.next, struct audit_tree, list);
+               get_tree(tree);
+               list_del(&cursor);
+               list_add(&cursor, &tree->list);
+               mutex_unlock(&audit_filter_mutex);
+
+               err = path_lookup(tree->pathname, 0, &nd);
+               if (err)
+                       goto skip_it;
+
+               root_mnt = collect_mounts(nd.mnt, nd.dentry);
+               path_release(&nd);
+               if (!root_mnt)
+                       goto skip_it;
+
+               list_add_tail(&list, &root_mnt->mnt_list);
+               spin_lock(&hash_lock);
+               list_for_each_entry(node, &tree->chunks, list) {
+                       struct audit_chunk *chunk = find_chunk(node);
+                       struct inode *inode = chunk->watch.inode;
+                       struct vfsmount *mnt;
+                       node->index |= 1U<<31;
+                       list_for_each_entry(mnt, &list, mnt_list) {
+                               if (mnt->mnt_root->d_inode == inode) {
+                                       node->index &= ~(1U<<31);
+                                       break;
+                               }
+                       }
+               }
+               spin_unlock(&hash_lock);
+               trim_marked(tree);
+               put_tree(tree);
+               list_del_init(&list);
+               drop_collected_mounts(root_mnt);
+skip_it:
+               mutex_lock(&audit_filter_mutex);
+       }
+       list_del(&cursor);
+       mutex_unlock(&audit_filter_mutex);
+}
+
+static int is_under(struct vfsmount *mnt, struct dentry *dentry,
+                   struct nameidata *nd)
+{
+       if (mnt != nd->mnt) {
+               for (;;) {
+                       if (mnt->mnt_parent == mnt)
+                               return 0;
+                       if (mnt->mnt_parent == nd->mnt)
+                                       break;
+                       mnt = mnt->mnt_parent;
+               }
+               dentry = mnt->mnt_mountpoint;
+       }
+       return is_subdir(dentry, nd->dentry);
+}
+
+int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
+{
+
+       if (pathname[0] != '/' ||
+           rule->listnr != AUDIT_FILTER_EXIT ||
+           op & ~AUDIT_EQUAL ||
+           rule->inode_f || rule->watch || rule->tree)
+               return -EINVAL;
+       rule->tree = alloc_tree(pathname);
+       if (!rule->tree)
+               return -ENOMEM;
+       return 0;
+}
+
+void audit_put_tree(struct audit_tree *tree)
+{
+       put_tree(tree);
+}
+
+/* called with audit_filter_mutex */
+int audit_add_tree_rule(struct audit_krule *rule)
+{
+       struct audit_tree *seed = rule->tree, *tree;
+       struct nameidata nd;
+       struct vfsmount *mnt, *p;
+       struct list_head list;
+       int err;
+
+       list_for_each_entry(tree, &tree_list, list) {
+               if (!strcmp(seed->pathname, tree->pathname)) {
+                       put_tree(seed);
+                       rule->tree = tree;
+                       list_add(&rule->rlist, &tree->rules);
+                       return 0;
+               }
+       }
+       tree = seed;
+       list_add(&tree->list, &tree_list);
+       list_add(&rule->rlist, &tree->rules);
+       /* do not set rule->tree yet */
+       mutex_unlock(&audit_filter_mutex);
+
+       err = path_lookup(tree->pathname, 0, &nd);
+       if (err)
+               goto Err;
+       mnt = collect_mounts(nd.mnt, nd.dentry);
+       path_release(&nd);
+       if (!mnt) {
+               err = -ENOMEM;
+               goto Err;
+       }
+       list_add_tail(&list, &mnt->mnt_list);
+
+       get_tree(tree);
+       list_for_each_entry(p, &list, mnt_list) {
+               err = tag_chunk(p->mnt_root->d_inode, tree);
+               if (err)
+                       break;
+       }
+
+       list_del(&list);
+       drop_collected_mounts(mnt);
+
+       if (!err) {
+               struct node *node;
+               spin_lock(&hash_lock);
+               list_for_each_entry(node, &tree->chunks, list)
+                       node->index &= ~(1U<<31);
+               spin_unlock(&hash_lock);
+       } else {
+               trim_marked(tree);
+               goto Err;
+       }
+
+       mutex_lock(&audit_filter_mutex);
+       if (list_empty(&rule->rlist)) {
+               put_tree(tree);
+               return -ENOENT;
+       }
+       rule->tree = tree;
+       put_tree(tree);
+
+       return 0;
+Err:
+       mutex_lock(&audit_filter_mutex);
+       list_del_init(&tree->list);
+       list_del_init(&tree->rules);
+       put_tree(tree);
+       return err;
+}
+
+int audit_tag_tree(char *old, char *new)
+{
+       struct list_head cursor, barrier;
+       int failed = 0;
+       struct nameidata nd;
+       struct vfsmount *tagged;
+       struct list_head list;
+       struct vfsmount *mnt;
+       struct dentry *dentry;
+       int err;
+
+       err = path_lookup(new, 0, &nd);
+       if (err)
+               return err;
+       tagged = collect_mounts(nd.mnt, nd.dentry);
+       path_release(&nd);
+       if (!tagged)
+               return -ENOMEM;
+
+       err = path_lookup(old, 0, &nd);
+       if (err) {
+               drop_collected_mounts(tagged);
+               return err;
+       }
+       mnt = mntget(nd.mnt);
+       dentry = dget(nd.dentry);
+       path_release(&nd);
+
+       if (dentry == tagged->mnt_root && dentry == mnt->mnt_root)
+               follow_up(&mnt, &dentry);
+
+       list_add_tail(&list, &tagged->mnt_list);
+
+       mutex_lock(&audit_filter_mutex);
+       list_add(&barrier, &tree_list);
+       list_add(&cursor, &barrier);
+
+       while (cursor.next != &tree_list) {
+               struct audit_tree *tree;
+               struct vfsmount *p;
+
+               tree = container_of(cursor.next, struct audit_tree, list);
+               get_tree(tree);
+               list_del(&cursor);
+               list_add(&cursor, &tree->list);
+               mutex_unlock(&audit_filter_mutex);
+
+               err = path_lookup(tree->pathname, 0, &nd);
+               if (err) {
+                       put_tree(tree);
+                       mutex_lock(&audit_filter_mutex);
+                       continue;
+               }
+
+               spin_lock(&vfsmount_lock);
+               if (!is_under(mnt, dentry, &nd)) {
+                       spin_unlock(&vfsmount_lock);
+                       path_release(&nd);
+                       put_tree(tree);
+                       mutex_lock(&audit_filter_mutex);
+                       continue;
+               }
+               spin_unlock(&vfsmount_lock);
+               path_release(&nd);
+
+               list_for_each_entry(p, &list, mnt_list) {
+                       failed = tag_chunk(p->mnt_root->d_inode, tree);
+                       if (failed)
+                               break;
+               }
+
+               if (failed) {
+                       put_tree(tree);
+                       mutex_lock(&audit_filter_mutex);
+                       break;
+               }
+
+               mutex_lock(&audit_filter_mutex);
+               spin_lock(&hash_lock);
+               if (!tree->goner) {
+                       list_del(&tree->list);
+                       list_add(&tree->list, &tree_list);
+               }
+               spin_unlock(&hash_lock);
+               put_tree(tree);
+       }
+
+       while (barrier.prev != &tree_list) {
+               struct audit_tree *tree;
+
+               tree = container_of(barrier.prev, struct audit_tree, list);
+               get_tree(tree);
+               list_del(&tree->list);
+               list_add(&tree->list, &barrier);
+               mutex_unlock(&audit_filter_mutex);
+
+               if (!failed) {
+                       struct node *node;
+                       spin_lock(&hash_lock);
+                       list_for_each_entry(node, &tree->chunks, list)
+                               node->index &= ~(1U<<31);
+                       spin_unlock(&hash_lock);
+               } else {
+                       trim_marked(tree);
+               }
+
+               put_tree(tree);
+               mutex_lock(&audit_filter_mutex);
+       }
+       list_del(&barrier);
+       list_del(&cursor);
+       list_del(&list);
+       mutex_unlock(&audit_filter_mutex);
+       dput(dentry);
+       mntput(mnt);
+       drop_collected_mounts(tagged);
+       return failed;
+}
+
+/*
+ * That gets run when evict_chunk() ends up needing to kill audit_tree.
+ * Runs from a separate thread, with audit_cmd_mutex held.
+ */
+void audit_prune_trees(void)
+{
+       mutex_lock(&audit_filter_mutex);
+
+       while (!list_empty(&prune_list)) {
+               struct audit_tree *victim;
+
+               victim = list_entry(prune_list.next, struct audit_tree, list);
+               list_del_init(&victim->list);
+
+               mutex_unlock(&audit_filter_mutex);
+
+               prune_one(victim);
+
+               mutex_lock(&audit_filter_mutex);
+       }
+
+       mutex_unlock(&audit_filter_mutex);
+}
+
+/*
+ *  Here comes the stuff asynchronous to auditctl operations
+ */
+
+/* inode->inotify_mutex is locked */
+static void evict_chunk(struct audit_chunk *chunk)
+{
+       struct audit_tree *owner;
+       int n;
+
+       if (chunk->dead)
+               return;
+
+       chunk->dead = 1;
+       mutex_lock(&audit_filter_mutex);
+       spin_lock(&hash_lock);
+       while (!list_empty(&chunk->trees)) {
+               owner = list_entry(chunk->trees.next,
+                                  struct audit_tree, same_root);
+               owner->goner = 1;
+               owner->root = NULL;
+               list_del_init(&owner->same_root);
+               spin_unlock(&hash_lock);
+               kill_rules(owner);
+               list_move(&owner->list, &prune_list);
+               audit_schedule_prune();
+               spin_lock(&hash_lock);
+       }
+       list_del_rcu(&chunk->hash);
+       for (n = 0; n < chunk->count; n++)
+               list_del_init(&chunk->owners[n].list);
+       spin_unlock(&hash_lock);
+       mutex_unlock(&audit_filter_mutex);
+}
+
+static void handle_event(struct inotify_watch *watch, u32 wd, u32 mask,
+                         u32 cookie, const char *dname, struct inode *inode)
+{
+       struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
+
+       if (mask & IN_IGNORED) {
+               evict_chunk(chunk);
+               put_inotify_watch(watch);
+       }
+}
+
+static void destroy_watch(struct inotify_watch *watch)
+{
+       struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
+       free_chunk(chunk);
+}
+
+static const struct inotify_operations rtree_inotify_ops = {
+       .handle_event   = handle_event,
+       .destroy_watch  = destroy_watch,
+};
+
+static int __init audit_tree_init(void)
+{
+       int i;
+
+       rtree_ih = inotify_init(&rtree_inotify_ops);
+       if (IS_ERR(rtree_ih))
+               audit_panic("cannot initialize inotify handle for rectree watches");
+
+       for (i = 0; i < HASH_SIZE; i++)
+               INIT_LIST_HEAD(&chunk_hash_heads[i]);
+
+       return 0;
+}
+__initcall(audit_tree_init);
index df66a21..5d96f2c 100644 (file)
@@ -87,7 +87,7 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
 #endif
 };
 
-static DEFINE_MUTEX(audit_filter_mutex);
+DEFINE_MUTEX(audit_filter_mutex);
 
 /* Inotify handle */
 extern struct inotify_handle *audit_ih;
@@ -145,7 +145,7 @@ static inline void audit_free_rule(struct audit_entry *e)
        kfree(e);
 }
 
-static inline void audit_free_rule_rcu(struct rcu_head *head)
+void audit_free_rule_rcu(struct rcu_head *head)
 {
        struct audit_entry *e = container_of(head, struct audit_entry, rcu);
        audit_free_rule(e);
@@ -217,7 +217,7 @@ static inline struct audit_entry *audit_init_entry(u32 field_count)
 
 /* Unpack a filter field's string representation from user-space
  * buffer. */
-static char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
+char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
 {
        char *str;
 
@@ -247,7 +247,7 @@ static inline int audit_to_inode(struct audit_krule *krule,
                                 struct audit_field *f)
 {
        if (krule->listnr != AUDIT_FILTER_EXIT ||
-           krule->watch || krule->inode_f)
+           krule->watch || krule->inode_f || krule->tree)
                return -EINVAL;
 
        krule->inode_f = f;
@@ -266,7 +266,7 @@ static int audit_to_watch(struct audit_krule *krule, char *path, int len,
        if (path[0] != '/' || path[len-1] == '/' ||
            krule->listnr != AUDIT_FILTER_EXIT ||
            op & ~AUDIT_EQUAL ||
-           krule->inode_f || krule->watch) /* 1 inode # per rule, for hash */
+           krule->inode_f || krule->watch || krule->tree)
                return -EINVAL;
 
        watch = audit_init_watch(path);
@@ -622,6 +622,17 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                                goto exit_free;
                        }
                        break;
+               case AUDIT_DIR:
+                       str = audit_unpack_string(&bufp, &remain, f->val);
+                       if (IS_ERR(str))
+                               goto exit_free;
+                       entry->rule.buflen += f->val;
+
+                       err = audit_make_tree(&entry->rule, str, f->op);
+                       kfree(str);
+                       if (err)
+                               goto exit_free;
+                       break;
                case AUDIT_INODE:
                        err = audit_to_inode(&entry->rule, f);
                        if (err)
@@ -668,7 +679,7 @@ exit_free:
 }
 
 /* Pack a filter field's string representation into data block. */
-static inline size_t audit_pack_string(void **bufp, char *str)
+static inline size_t audit_pack_string(void **bufp, const char *str)
 {
        size_t len = strlen(str);
 
@@ -747,6 +758,11 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
                        data->buflen += data->values[i] =
                                audit_pack_string(&bufp, krule->watch->path);
                        break;
+               case AUDIT_DIR:
+                       data->buflen += data->values[i] =
+                               audit_pack_string(&bufp,
+                                                 audit_tree_path(krule->tree));
+                       break;
                case AUDIT_FILTERKEY:
                        data->buflen += data->values[i] =
                                audit_pack_string(&bufp, krule->filterkey);
@@ -795,6 +811,11 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
                        if (strcmp(a->watch->path, b->watch->path))
                                return 1;
                        break;
+               case AUDIT_DIR:
+                       if (strcmp(audit_tree_path(a->tree),
+                                  audit_tree_path(b->tree)))
+                               return 1;
+                       break;
                case AUDIT_FILTERKEY:
                        /* both filterkeys exist based on above type compare */
                        if (strcmp(a->filterkey, b->filterkey))
@@ -897,6 +918,14 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
        new->inode_f = old->inode_f;
        new->watch = NULL;
        new->field_count = old->field_count;
+       /*
+        * note that we are OK with not refcounting here; audit_match_tree()
+        * never dereferences tree and we can't get false positives there
+        * since we'd have to have rule gone from the list *and* removed
+        * before the chunks found by lookup had been allocated, i.e. before
+        * the beginning of list scan.
+        */
+       new->tree = old->tree;
        memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
 
        /* deep copy this information, updating the se_rule fields, because
@@ -1217,6 +1246,7 @@ static inline int audit_add_rule(struct audit_entry *entry,
        struct audit_entry *e;
        struct audit_field *inode_f = entry->rule.inode_f;
        struct audit_watch *watch = entry->rule.watch;
+       struct audit_tree *tree = entry->rule.tree;
        struct nameidata *ndp = NULL, *ndw = NULL;
        int h, err;
 #ifdef CONFIG_AUDITSYSCALL
@@ -1238,6 +1268,9 @@ static inline int audit_add_rule(struct audit_entry *entry,
        mutex_unlock(&audit_filter_mutex);
        if (e) {
                err = -EEXIST;
+               /* normally audit_add_tree_rule() will free it on failure */
+               if (tree)
+                       audit_put_tree(tree);
                goto error;
        }
 
@@ -1259,6 +1292,13 @@ static inline int audit_add_rule(struct audit_entry *entry,
                h = audit_hash_ino((u32)watch->ino);
                list = &audit_inode_hash[h];
        }
+       if (tree) {
+               err = audit_add_tree_rule(&entry->rule);
+               if (err) {
+                       mutex_unlock(&audit_filter_mutex);
+                       goto error;
+               }
+       }
 
        if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
                list_add_rcu(&entry->list, list);
@@ -1292,6 +1332,7 @@ static inline int audit_del_rule(struct audit_entry *entry,
        struct audit_entry  *e;
        struct audit_field *inode_f = entry->rule.inode_f;
        struct audit_watch *watch, *tmp_watch = entry->rule.watch;
+       struct audit_tree *tree = entry->rule.tree;
        LIST_HEAD(inotify_list);
        int h, ret = 0;
 #ifdef CONFIG_AUDITSYSCALL
@@ -1336,6 +1377,9 @@ static inline int audit_del_rule(struct audit_entry *entry,
                }
        }
 
+       if (e->rule.tree)
+               audit_remove_tree_rule(&e->rule);
+
        list_del_rcu(&e->list);
        call_rcu(&e->rcu, audit_free_rule_rcu);
 
@@ -1354,6 +1398,8 @@ static inline int audit_del_rule(struct audit_entry *entry,
 out:
        if (tmp_watch)
                audit_put_watch(tmp_watch); /* match initial get */
+       if (tree)
+               audit_put_tree(tree);   /* that's the temporary one */
 
        return ret;
 }
@@ -1737,6 +1783,7 @@ int selinux_audit_rule_update(void)
 {
        struct audit_entry *entry, *n, *nentry;
        struct audit_watch *watch;
+       struct audit_tree *tree;
        int i, err = 0;
 
        /* audit_filter_mutex synchronizes the writers */
@@ -1748,6 +1795,7 @@ int selinux_audit_rule_update(void)
                                continue;
 
                        watch = entry->rule.watch;
+                       tree = entry->rule.tree;
                        nentry = audit_dupe_rule(&entry->rule, watch);
                        if (unlikely(IS_ERR(nentry))) {
                                /* save the first error encountered for the
@@ -1763,7 +1811,9 @@ int selinux_audit_rule_update(void)
                                        list_add(&nentry->rule.rlist,
                                                 &watch->rules);
                                        list_del(&entry->rule.rlist);
-                               }
+                               } else if (tree)
+                                       list_replace_init(&entry->rule.rlist,
+                                                    &nentry->rule.rlist);
                                list_replace_rcu(&entry->list, &nentry->list);
                        }
                        call_rcu(&entry->rcu, audit_free_rule_rcu);
index e19b5a3..bce9ecd 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/binfmts.h>
 #include <linux/highmem.h>
 #include <linux/syscalls.h>
+#include <linux/inotify.h>
 
 #include "audit.h"
 
@@ -179,6 +180,11 @@ struct audit_aux_data_pids {
        int                     pid_count;
 };
 
+struct audit_tree_refs {
+       struct audit_tree_refs *next;
+       struct audit_chunk *c[31];
+};
+
 /* The per-task audit context. */
 struct audit_context {
        int                 dummy;      /* must be the first element */
@@ -211,6 +217,9 @@ struct audit_context {
        pid_t               target_pid;
        u32                 target_sid;
 
+       struct audit_tree_refs *trees, *first_trees;
+       int tree_count;
+
 #if AUDIT_DEBUG
        int                 put_count;
        int                 ino_count;
@@ -265,6 +274,117 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
        }
 }
 
+/*
+ * We keep a linked list of fixed-sized (31 pointer) arrays of audit_chunk *;
+ * ->first_trees points to its beginning, ->trees - to the current end of data.
+ * ->tree_count is the number of free entries in array pointed to by ->trees.
+ * Original condition is (NULL, NULL, 0); as soon as it grows we never revert to NULL,
+ * "empty" becomes (p, p, 31) afterwards.  We don't shrink the list (and seriously,
+ * it's going to remain 1-element for almost any setup) until we free context itself.
+ * References in it _are_ dropped - at the same time we free/drop aux stuff.
+ */
+
+#ifdef CONFIG_AUDIT_TREE
+static int put_tree_ref(struct audit_context *ctx, struct audit_chunk *chunk)
+{
+       struct audit_tree_refs *p = ctx->trees;
+       int left = ctx->tree_count;
+       if (likely(left)) {
+               p->c[--left] = chunk;
+               ctx->tree_count = left;
+               return 1;
+       }
+       if (!p)
+               return 0;
+       p = p->next;
+       if (p) {
+               p->c[30] = chunk;
+               ctx->trees = p;
+               ctx->tree_count = 30;
+               return 1;
+       }
+       return 0;
+}
+
+static int grow_tree_refs(struct audit_context *ctx)
+{
+       struct audit_tree_refs *p = ctx->trees;
+       ctx->trees = kzalloc(sizeof(struct audit_tree_refs), GFP_KERNEL);
+       if (!ctx->trees) {
+               ctx->trees = p;
+               return 0;
+       }
+       if (p)
+               p->next = ctx->trees;
+       else
+               ctx->first_trees = ctx->trees;
+       ctx->tree_count = 31;
+       return 1;
+}
+#endif
+
+static void unroll_tree_refs(struct audit_context *ctx,
+                     struct audit_tree_refs *p, int count)
+{
+#ifdef CONFIG_AUDIT_TREE
+       struct audit_tree_refs *q;
+       int n;
+       if (!p) {
+               /* we started with empty chain */
+               p = ctx->first_trees;
+               count = 31;
+               /* if the very first allocation has failed, nothing to do */
+               if (!p)
+                       return;
+       }
+       n = count;
+       for (q = p; q != ctx->trees; q = q->next, n = 31) {
+               while (n--) {
+                       audit_put_chunk(q->c[n]);
+                       q->c[n] = NULL;
+               }
+       }
+       while (n-- > ctx->tree_count) {
+               audit_put_chunk(q->c[n]);
+               q->c[n] = NULL;
+       }
+       ctx->trees = p;
+       ctx->tree_count = count;
+#endif
+}
+
+static void free_tree_refs(struct audit_context *ctx)
+{
+       struct audit_tree_refs *p, *q;
+       for (p = ctx->first_trees; p; p = q) {
+               q = p->next;
+               kfree(p);
+       }
+}
+
+static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
+{
+#ifdef CONFIG_AUDIT_TREE
+       struct audit_tree_refs *p;
+       int n;
+       if (!tree)
+               return 0;
+       /* full ones */
+       for (p = ctx->first_trees; p != ctx->trees; p = p->next) {
+               for (n = 0; n < 31; n++)
+                       if (audit_tree_match(p->c[n], tree))
+                               return 1;
+       }
+       /* partial */
+       if (p) {
+               for (n = ctx->tree_count; n < 31; n++)
+                       if (audit_tree_match(p->c[n], tree))
+                               return 1;
+       }
+#endif
+       return 0;
+}
+
 /* Determine if any context name data matches a rule's watch data */
 /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
  * otherwise. */
@@ -379,6 +499,10 @@ static int audit_filter_rules(struct task_struct *tsk,
                                result = (name->dev == rule->watch->dev &&
                                          name->ino == rule->watch->ino);
                        break;
+               case AUDIT_DIR:
+                       if (ctx)
+                               result = match_tree_refs(ctx, rule->tree);
+                       break;
                case AUDIT_LOGINUID:
                        result = 0;
                        if (ctx)
@@ -727,6 +851,8 @@ static inline void audit_free_context(struct audit_context *context)
                               context->name_count, count);
                }
                audit_free_names(context);
+               unroll_tree_refs(context, NULL, 0);
+               free_tree_refs(context);
                audit_free_aux(context);
                kfree(context->filterkey);
                kfree(context);
@@ -1270,6 +1396,7 @@ void audit_syscall_exit(int valid, long return_code)
                tsk->audit_context = new_context;
        } else {
                audit_free_names(context);
+               unroll_tree_refs(context, NULL, 0);
                audit_free_aux(context);
                context->aux = NULL;
                context->aux_pids = NULL;
@@ -1281,6 +1408,95 @@ void audit_syscall_exit(int valid, long return_code)
        }
 }
 
+static inline void handle_one(const struct inode *inode)
+{
+#ifdef CONFIG_AUDIT_TREE
+       struct audit_context *context;
+       struct audit_tree_refs *p;
+       struct audit_chunk *chunk;
+       int count;
+       if (likely(list_empty(&inode->inotify_watches)))
+               return;
+       context = current->audit_context;
+       p = context->trees;
+       count = context->tree_count;
+       rcu_read_lock();
+       chunk = audit_tree_lookup(inode);
+       rcu_read_unlock();
+       if (!chunk)
+               return;
+       if (likely(put_tree_ref(context, chunk)))
+               return;
+       if (unlikely(!grow_tree_refs(context))) {
+               printk(KERN_WARNING "out of memory, audit has lost a tree reference");
+               audit_set_auditable(context);
+               audit_put_chunk(chunk);
+               unroll_tree_refs(context, p, count);
+               return;
+       }
+       put_tree_ref(context, chunk);
+#endif
+}
+
+static void handle_path(const struct dentry *dentry)
+{
+#ifdef CONFIG_AUDIT_TREE
+       struct audit_context *context;
+       struct audit_tree_refs *p;
+       const struct dentry *d, *parent;
+       struct audit_chunk *drop;
+       unsigned long seq;
+       int count;
+
+       context = current->audit_context;
+       p = context->trees;
+       count = context->tree_count;
+retry:
+       drop = NULL;
+       d = dentry;
+       rcu_read_lock();
+       seq = read_seqbegin(&rename_lock);
+       for(;;) {
+               struct inode *inode = d->d_inode;
+               if (inode && unlikely(!list_empty(&inode->inotify_watches))) {
+                       struct audit_chunk *chunk;
+                       chunk = audit_tree_lookup(inode);
+                       if (chunk) {
+                               if (unlikely(!put_tree_ref(context, chunk))) {
+                                       drop = chunk;
+                                       break;
+                               }
+                       }
+               }
+               parent = d->d_parent;
+               if (parent == d)
+                       break;
+               d = parent;
+       }
+       if (unlikely(read_seqretry(&rename_lock, seq) || drop)) {  /* in this order */
+               rcu_read_unlock();
+               if (!drop) {
+                       /* just a race with rename */
+                       unroll_tree_refs(context, p, count);
+                       goto retry;
+               }
+               audit_put_chunk(drop);
+               if (grow_tree_refs(context)) {
+                       /* OK, got more space */
+                       unroll_tree_refs(context, p, count);
+                       goto retry;
+               }
+               /* too bad */
+               printk(KERN_WARNING
+                       "out of memory, audit has lost a tree reference");
+               unroll_tree_refs(context, p, count);
+               audit_set_auditable(context);
+               return;
+       }
+       rcu_read_unlock();
+#endif
+}
+
 /**
  * audit_getname - add a name to the list
  * @name: name to add
@@ -1399,14 +1615,15 @@ static void audit_copy_inode(struct audit_names *name, const struct inode *inode
 /**
  * audit_inode - store the inode and device from a lookup
  * @name: name being audited
- * @inode: inode being audited
+ * @dentry: dentry being audited
  *
  * Called from fs/namei.c:path_lookup().
  */
-void __audit_inode(const char *name, const struct inode *inode)
+void __audit_inode(const char *name, const struct dentry *dentry)
 {
        int idx;
        struct audit_context *context = current->audit_context;
+       const struct inode *inode = dentry->d_inode;
 
        if (!context->in_syscall)
                return;
@@ -1426,13 +1643,14 @@ void __audit_inode(const char *name, const struct inode *inode)
                idx = context->name_count - 1;
                context->names[idx].name = NULL;
        }
+       handle_path(dentry);
        audit_copy_inode(&context->names[idx], inode);
 }
 
 /**
  * audit_inode_child - collect inode info for created/removed objects
  * @dname: inode's dentry name
- * @inode: inode being audited
+ * @dentry: dentry being audited
  * @parent: inode of dentry parent
  *
  * For syscalls that create or remove filesystem objects, audit_inode
@@ -1443,17 +1661,20 @@ void __audit_inode(const char *name, const struct inode *inode)
  * must be hooked prior, in order to capture the target inode during
  * unsuccessful attempts.
  */
-void __audit_inode_child(const char *dname, const struct inode *inode,
+void __audit_inode_child(const char *dname, const struct dentry *dentry,
                         const struct inode *parent)
 {
        int idx;
        struct audit_context *context = current->audit_context;
        const char *found_parent = NULL, *found_child = NULL;
+       const struct inode *inode = dentry->d_inode;
        int dirlen = 0;
 
        if (!context->in_syscall)
                return;
 
+       if (inode)
+               handle_one(inode);
        /* determine matching parent */
        if (!dname)
                goto add_names;
index 80eab7a..1f31422 100644 (file)
 void synchronize_irq(unsigned int irq)
 {
        struct irq_desc *desc = irq_desc + irq;
+       unsigned int status;
 
        if (irq >= NR_IRQS)
                return;
 
-       while (desc->status & IRQ_INPROGRESS)
-               cpu_relax();
+       do {
+               unsigned long flags;
+
+               /*
+                * Wait until we're out of the critical section.  This might
+                * give the wrong answer due to the lack of memory barriers.
+                */
+               while (desc->status & IRQ_INPROGRESS)
+                       cpu_relax();
+
+               /* Ok, that indicated we're done: double-check carefully. */
+               spin_lock_irqsave(&desc->lock, flags);
+               status = desc->status;
+               spin_unlock_irqrestore(&desc->lock, flags);
+
+               /* Oops, that failed? */
+       } while (status & IRQ_INPROGRESS);
 }
 EXPORT_SYMBOL(synchronize_irq);
 
index 7581e33..2810e56 100644 (file)
@@ -3375,7 +3375,6 @@ void account_system_time(struct task_struct *p, int hardirq_offset,
 
        if (p->flags & PF_VCPU) {
                account_guest_time(p, cputime);
-               p->flags &= ~PF_VCPU;
                return;
        }
 
index 3c9ef5a..ed6fe51 100644 (file)
@@ -731,7 +731,7 @@ static struct trans_ctl_table trans_net_table[] = {
        { NET_UNIX,             "unix",         trans_net_unix_table },
        { NET_IPV4,             "ipv4",         trans_net_ipv4_table },
        { NET_IPX,              "ipx",          trans_net_ipx_table },
-       { NET_ATALK,            "atalk",        trans_net_atalk_table },
+       { NET_ATALK,            "appletalk",    trans_net_atalk_table },
        { NET_NETROM,           "netrom",       trans_net_netrom_table },
        { NET_AX25,             "ax25",         trans_net_ax25_table },
        { NET_BRIDGE,           "bridge",       trans_net_bridge_table },
index c567f21..1faa508 100644 (file)
@@ -389,6 +389,16 @@ config DEBUG_LIST
 
          If unsure, say N.
 
+config DEBUG_SG
+       bool "Debug SG table operations"
+       depends on DEBUG_KERNEL
+       help
+         Enable this to turn on checks on scatter-gather tables. This can
+         help find problems with drivers that do not properly initialize
+         their sg tables.
+
+         If unsure, say N.
+
 config FRAME_POINTER
        bool "Compile the kernel with frame pointers"
        depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH || BFIN)
index a58df56..0ec3f25 100644 (file)
@@ -39,8 +39,7 @@
 
        /* Check length parameter for validity */
        pad = nn - nroots - len;
-       if (pad < 0 || pad >= nn)
-               return -ERANGE;
+       BUG_ON(pad < 0 || pad >= nn);
 
        /* Does the caller provide the syndrome ? */
        if (s != NULL)
                 * deg(lambda) unequal to number of roots => uncorrectable
                 * error detected
                 */
-               count = -1;
+               count = -EBADMSG;
                goto finish;
        }
        /*
index 5b0d852..3ea2db9 100644 (file)
@@ -320,6 +320,7 @@ EXPORT_SYMBOL_GPL(encode_rs8);
  *  The syndrome and parity uses a uint16_t data type to enable
  *  symbol size > 8. The calling code must take care of decoding of the
  *  syndrome result and the received parity before calling this code.
+ *  Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
  */
 int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
               uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
@@ -363,6 +364,7 @@ EXPORT_SYMBOL_GPL(encode_rs16);
  *  @corr:     buffer to store correction bitmask on eras_pos
  *
  *  Each field in the data array contains up to symbol size bits of valid data.
+ *  Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
  */
 int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
                uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
index 752fd95..1a8050a 100644 (file)
@@ -35,7 +35,7 @@
 #define OFFSET(val,align) ((unsigned long)     \
                           ( (val) & ( (align) - 1)))
 
-#define SG_ENT_VIRT_ADDRESS(sg)        (page_address((sg)->page) + (sg)->offset)
+#define SG_ENT_VIRT_ADDRESS(sg)        (sg_virt((sg)))
 #define SG_ENT_PHYS_ADDRESS(sg)        virt_to_bus(SG_ENT_VIRT_ADDRESS(sg))
 
 /*
index 1833879..3a47871 100644 (file)
@@ -187,7 +187,24 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
        unsigned long onlined_pages = 0;
        struct zone *zone;
        int need_zonelists_rebuild = 0;
+       int nid;
+       int ret;
+       struct memory_notify arg;
+
+       arg.start_pfn = pfn;
+       arg.nr_pages = nr_pages;
+       arg.status_change_nid = -1;
+
+       nid = page_to_nid(pfn_to_page(pfn));
+       if (node_present_pages(nid) == 0)
+               arg.status_change_nid = nid;
 
+       ret = memory_notify(MEM_GOING_ONLINE, &arg);
+       ret = notifier_to_errno(ret);
+       if (ret) {
+               memory_notify(MEM_CANCEL_ONLINE, &arg);
+               return ret;
+       }
        /*
         * This doesn't need a lock to do pfn_to_page().
         * The section can't be removed here because of the
@@ -222,6 +239,10 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
                build_all_zonelists();
        vm_total_pages = nr_free_pagecache_pages();
        writeback_set_ratelimit();
+
+       if (onlined_pages)
+               memory_notify(MEM_ONLINE, &arg);
+
        return 0;
 }
 #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
@@ -467,8 +488,9 @@ int offline_pages(unsigned long start_pfn,
 {
        unsigned long pfn, nr_pages, expire;
        long offlined_pages;
-       int ret, drain, retry_max;
+       int ret, drain, retry_max, node;
        struct zone *zone;
+       struct memory_notify arg;
 
        BUG_ON(start_pfn >= end_pfn);
        /* at least, alignment against pageblock is necessary */
@@ -480,11 +502,27 @@ int offline_pages(unsigned long start_pfn,
           we assume this for now. .*/
        if (!test_pages_in_a_zone(start_pfn, end_pfn))
                return -EINVAL;
+
+       zone = page_zone(pfn_to_page(start_pfn));
+       node = zone_to_nid(zone);
+       nr_pages = end_pfn - start_pfn;
+
        /* set above range as isolated */
        ret = start_isolate_page_range(start_pfn, end_pfn);
        if (ret)
                return ret;
-       nr_pages = end_pfn - start_pfn;
+
+       arg.start_pfn = start_pfn;
+       arg.nr_pages = nr_pages;
+       arg.status_change_nid = -1;
+       if (nr_pages >= node_present_pages(node))
+               arg.status_change_nid = node;
+
+       ret = memory_notify(MEM_GOING_OFFLINE, &arg);
+       ret = notifier_to_errno(ret);
+       if (ret)
+               goto failed_removal;
+
        pfn = start_pfn;
        expire = jiffies + timeout;
        drain = 0;
@@ -539,20 +577,24 @@ repeat:
        /* reset pagetype flags */
        start_isolate_page_range(start_pfn, end_pfn);
        /* removal success */
-       zone = page_zone(pfn_to_page(start_pfn));
        zone->present_pages -= offlined_pages;
        zone->zone_pgdat->node_present_pages -= offlined_pages;
        totalram_pages -= offlined_pages;
        num_physpages -= offlined_pages;
+
        vm_total_pages = nr_free_pagecache_pages();
        writeback_set_ratelimit();
+
+       memory_notify(MEM_OFFLINE, &arg);
        return 0;
 
 failed_removal:
        printk(KERN_INFO "memory offlining %lx to %lx failed\n",
                start_pfn, end_pfn);
+       memory_notify(MEM_CANCEL_OFFLINE, &arg);
        /* pushback to free area */
        undo_isolate_page_range(start_pfn, end_pfn);
+
        return ret;
 }
 #else
index 7a30c49..facc1a7 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1171,8 +1171,7 @@ munmap_back:
        vm_flags = vma->vm_flags;
 
        if (vma_wants_writenotify(vma))
-               vma->vm_page_prot =
-                       protection_map[vm_flags & (VM_READ|VM_WRITE|VM_EXEC)];
+               vma->vm_page_prot = vm_get_page_prot(vm_flags & ~VM_SHARED);
 
        if (!file || !vma_merge(mm, prev, addr, vma->vm_end,
                        vma->vm_flags, NULL, file, pgoff, vma_policy(vma))) {
index 5522784..4de5468 100644 (file)
@@ -194,7 +194,7 @@ success:
        vma->vm_flags = newflags;
        vma->vm_page_prot = vm_get_page_prot(newflags);
        if (vma_wants_writenotify(vma)) {
-               vma->vm_page_prot = vm_get_page_prot(newflags);
+               vma->vm_page_prot = vm_get_page_prot(newflags & ~VM_SHARED);
                dirty_accountable = 1;
        }
 
index 824cade..91a081a 100644 (file)
@@ -496,7 +496,7 @@ retry:
                        panic("Out of memory and no killable processes...\n");
                }
 
-               if (oom_kill_process(p, points, gfp_mask, order,
+               if (oom_kill_process(p, gfp_mask, order, points,
                                     "Out of memory"))
                        goto retry;
 
index 289dbb0..404e53b 100644 (file)
@@ -2020,33 +2020,25 @@ static int shmem_match(struct inode *ino, void *vfh)
        return ino->i_ino == inum && fh[0] == ino->i_generation;
 }
 
-static struct dentry *shmem_get_dentry(struct super_block *sb, void *vfh)
+static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
+               struct fid *fid, int fh_len, int fh_type)
 {
-       struct dentry *de = NULL;
        struct inode *inode;
-       __u32 *fh = vfh;
-       __u64 inum = fh[2];
-       inum = (inum << 32) | fh[1];
+       struct dentry *dentry = NULL;
+       u64 inum = fid->raw[2];
+       inum = (inum << 32) | fid->raw[1];
+
+       if (fh_len < 3)
+               return NULL;
 
-       inode = ilookup5(sb, (unsigned long)(inum+fh[0]), shmem_match, vfh);
+       inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]),
+                       shmem_match, fid->raw);
        if (inode) {
-               de = d_find_alias(inode);
+               dentry = d_find_alias(inode);
                iput(inode);
        }
 
-       return de? de: ERR_PTR(-ESTALE);
-}
-
-static struct dentry *shmem_decode_fh(struct super_block *sb, __u32 *fh,
-               int len, int type,
-               int (*acceptable)(void *context, struct dentry *de),
-               void *context)
-{
-       if (len < 3)
-               return ERR_PTR(-ESTALE);
-
-       return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable,
-                                                       context);
+       return dentry;
 }
 
 static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
@@ -2079,11 +2071,10 @@ static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
        return 1;
 }
 
-static struct export_operations shmem_export_ops = {
+static const struct export_operations shmem_export_ops = {
        .get_parent     = shmem_get_parent,
-       .get_dentry     = shmem_get_dentry,
        .encode_fh      = shmem_encode_fh,
-       .decode_fh      = shmem_decode_fh,
+       .fh_to_dentry   = shmem_fh_to_dentry,
 };
 
 static int shmem_parse_options(char *options, int *mode, uid_t *uid,
index e29a429..aac1dd3 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -20,6 +20,7 @@
 #include <linux/mempolicy.h>
 #include <linux/ctype.h>
 #include <linux/kallsyms.h>
+#include <linux/memory.h>
 
 /*
  * Lock order:
@@ -2694,6 +2695,121 @@ int kmem_cache_shrink(struct kmem_cache *s)
 }
 EXPORT_SYMBOL(kmem_cache_shrink);
 
+#if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG)
+static int slab_mem_going_offline_callback(void *arg)
+{
+       struct kmem_cache *s;
+
+       down_read(&slub_lock);
+       list_for_each_entry(s, &slab_caches, list)
+               kmem_cache_shrink(s);
+       up_read(&slub_lock);
+
+       return 0;
+}
+
+static void slab_mem_offline_callback(void *arg)
+{
+       struct kmem_cache_node *n;
+       struct kmem_cache *s;
+       struct memory_notify *marg = arg;
+       int offline_node;
+
+       offline_node = marg->status_change_nid;
+
+       /*
+        * If the node still has available memory. we need kmem_cache_node
+        * for it yet.
+        */
+       if (offline_node < 0)
+               return;
+
+       down_read(&slub_lock);
+       list_for_each_entry(s, &slab_caches, list) {
+               n = get_node(s, offline_node);
+               if (n) {
+                       /*
+                        * if n->nr_slabs > 0, slabs still exist on the node
+                        * that is going down. We were unable to free them,
+                        * and offline_pages() function shoudn't call this
+                        * callback. So, we must fail.
+                        */
+                       BUG_ON(atomic_read(&n->nr_slabs));
+
+                       s->node[offline_node] = NULL;
+                       kmem_cache_free(kmalloc_caches, n);
+               }
+       }
+       up_read(&slub_lock);
+}
+
+static int slab_mem_going_online_callback(void *arg)
+{
+       struct kmem_cache_node *n;
+       struct kmem_cache *s;
+       struct memory_notify *marg = arg;
+       int nid = marg->status_change_nid;
+       int ret = 0;
+
+       /*
+        * If the node's memory is already available, then kmem_cache_node is
+        * already created. Nothing to do.
+        */
+       if (nid < 0)
+               return 0;
+
+       /*
+        * We are bringing a node online. No memory is availabe yet. We must
+        * allocate a kmem_cache_node structure in order to bring the node
+        * online.
+        */
+       down_read(&slub_lock);
+       list_for_each_entry(s, &slab_caches, list) {
+               /*
+                * XXX: kmem_cache_alloc_node will fallback to other nodes
+                *      since memory is not yet available from the node that
+                *      is brought up.
+                */
+               n = kmem_cache_alloc(kmalloc_caches, GFP_KERNEL);
+               if (!n) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               init_kmem_cache_node(n);
+               s->node[nid] = n;
+       }
+out:
+       up_read(&slub_lock);
+       return ret;
+}
+
+static int slab_memory_callback(struct notifier_block *self,
+                               unsigned long action, void *arg)
+{
+       int ret = 0;
+
+       switch (action) {
+       case MEM_GOING_ONLINE:
+               ret = slab_mem_going_online_callback(arg);
+               break;
+       case MEM_GOING_OFFLINE:
+               ret = slab_mem_going_offline_callback(arg);
+               break;
+       case MEM_OFFLINE:
+       case MEM_CANCEL_ONLINE:
+               slab_mem_offline_callback(arg);
+               break;
+       case MEM_ONLINE:
+       case MEM_CANCEL_OFFLINE:
+               break;
+       }
+
+       ret = notifier_from_errno(ret);
+       return ret;
+}
+
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
 /********************************************************************
  *                     Basic setup of slabs
  *******************************************************************/
@@ -2715,6 +2831,8 @@ void __init kmem_cache_init(void)
                sizeof(struct kmem_cache_node), GFP_KERNEL);
        kmalloc_caches[0].refcount = -1;
        caches++;
+
+       hotplug_memory_notifier(slab_memory_callback, 1);
 #endif
 
        /* Able to allocate the per node structures */
index 71bc110..bafc50c 100644 (file)
@@ -23,6 +23,13 @@ config NET_9P_FD
          file descriptors.  TCP/IP is the default transport for 9p,
          so if you are going to use 9p, you'll likely want this.
 
+config NET_9P_VIRTIO
+       depends on NET_9P && EXPERIMENTAL && VIRTIO
+       tristate "9P Virtio Transport (Experimental)"
+       help
+         This builds support for a transports between
+         guest partitions and a host partition.
+
 config NET_9P_DEBUG
        bool "Debug information"
        depends on NET_9P
index 5059bc0..d3abb24 100644 (file)
@@ -1,5 +1,6 @@
 obj-$(CONFIG_NET_9P) := 9pnet.o
 obj-$(CONFIG_NET_9P_FD) += 9pnet_fd.o
+obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o
 
 9pnet-objs := \
        mod.o \
@@ -12,3 +13,6 @@ obj-$(CONFIG_NET_9P_FD) += 9pnet_fd.o
 
 9pnet_fd-objs := \
        trans_fd.o \
+
+9pnet_virtio-objs := \
+       trans_virtio.o \
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
new file mode 100644 (file)
index 0000000..40b71a2
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * The Guest 9p transport driver
+ *
+ * This is a trivial pipe-based transport driver based on the lguest console
+ * code: we use lguest's DMA mechanism to send bytes out, and register a
+ * DMA buffer to receive bytes in.  It is assumed to be present and available
+ * from the very beginning of boot.
+ *
+ * This may be have been done by just instaniating another HVC console,
+ * but HVC's blocksize of 16 bytes is annoying and painful to performance.
+ *
+ * A more efficient transport could be built based on the virtio block driver
+ * but it requires some changes in the 9p transport model (which are in
+ * progress)
+ *
+ */
+/*
+ *  Copyright (C) 2007 Eric Van Hensbergen, IBM Corporation
+ *
+ *  Based on virtio console driver
+ *  Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  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:
+ *  Free Software Foundation
+ *  51 Franklin Street, Fifth Floor
+ *  Boston, MA  02111-1301  USA
+ *
+ */
+
+#include <linux/in.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/ipv6.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/un.h>
+#include <linux/uaccess.h>
+#include <linux/inet.h>
+#include <linux/idr.h>
+#include <linux/file.h>
+#include <net/9p/9p.h>
+#include <linux/parser.h>
+#include <net/9p/transport.h>
+#include <linux/scatterlist.h>
+#include <linux/virtio.h>
+#include <linux/virtio_9p.h>
+
+/* a single mutex to manage channel initialization and attachment */
+static DECLARE_MUTEX(virtio_9p_lock);
+/* global which tracks highest initialized channel */
+static int chan_index;
+
+/* We keep all per-channel information in a structure.
+ * This structure is allocated within the devices dev->mem space.
+ * A pointer to the structure will get put in the transport private.
+ */
+static struct virtio_chan {
+       bool initialized;               /* channel is initialized */
+       bool inuse;                     /* channel is in use */
+
+       struct virtqueue *in_vq, *out_vq;
+       struct virtio_device *vdev;
+
+       /* This is our input buffer, and how much data is left in it. */
+       unsigned int in_len;
+       char *in, *inbuf;
+
+       wait_queue_head_t wq;           /* waitq for buffer */
+} channels[MAX_9P_CHAN];
+
+/* How many bytes left in this page. */
+static unsigned int rest_of_page(void *data)
+{
+       return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
+}
+
+static int p9_virtio_write(struct p9_trans *trans, void *buf, int count)
+{
+       struct virtio_chan *chan = (struct virtio_chan *) trans->priv;
+       struct virtqueue *out_vq = chan->out_vq;
+       struct scatterlist sg[1];
+       unsigned int len;
+
+       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio write (%d)\n", count);
+
+       /* keep it simple - make sure we don't overflow a page */
+       if (rest_of_page(buf) < count)
+               count = rest_of_page(buf);
+
+       sg_init_one(sg, buf, count);
+
+       /* add_buf wants a token to identify this buffer: we hand it any
+        * non-NULL pointer, since there's only ever one buffer. */
+       if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) == 0) {
+               /* Tell Host to go! */
+               out_vq->vq_ops->kick(out_vq);
+               /* Chill out until it's done with the buffer. */
+               while (!out_vq->vq_ops->get_buf(out_vq, &len))
+                       cpu_relax();
+       }
+
+       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio wrote (%d)\n", count);
+
+       /* We're expected to return the amount of data we wrote: all of it. */
+       return count;
+}
+
+/* Create a scatter-gather list representing our input buffer and put it in the
+ * queue. */
+static void add_inbuf(struct virtio_chan *chan)
+{
+       struct scatterlist sg[1];
+
+       sg_init_one(sg, chan->inbuf, PAGE_SIZE);
+
+       /* We should always be able to add one buffer to an empty queue. */
+       if (chan->in_vq->vq_ops->add_buf(chan->in_vq, sg, 0, 1, chan->inbuf))
+               BUG();
+       chan->in_vq->vq_ops->kick(chan->in_vq);
+}
+
+static int p9_virtio_read(struct p9_trans *trans, void *buf, int count)
+{
+       struct virtio_chan *chan = (struct virtio_chan *) trans->priv;
+       struct virtqueue *in_vq = chan->in_vq;
+
+       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio read (%d)\n", count);
+
+       /* If we don't have an input queue yet, we can't get input. */
+       BUG_ON(!in_vq);
+
+       /* No buffer?  Try to get one. */
+       if (!chan->in_len) {
+               chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);
+               if (!chan->in)
+                       return 0;
+       }
+
+       /* You want more than we have to give?  Well, try wanting less! */
+       if (chan->in_len < count)
+               count = chan->in_len;
+
+       /* Copy across to their buffer and increment offset. */
+       memcpy(buf, chan->in, count);
+       chan->in += count;
+       chan->in_len -= count;
+
+       /* Finished?  Re-register buffer so Host will use it again. */
+       if (chan->in_len == 0)
+               add_inbuf(chan);
+
+       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio finished read (%d)\n",
+                                                                       count);
+
+       return count;
+}
+
+/* The poll function is used by 9p transports to determine if there
+ * is there is activity available on a particular channel.  In our case
+ * we use it to wait for a callback from the input routines.
+ */
+static unsigned int
+p9_virtio_poll(struct p9_trans *trans, struct poll_table_struct *pt)
+{
+       struct virtio_chan *chan = (struct virtio_chan *)trans->priv;
+       struct virtqueue *in_vq = chan->in_vq;
+       int ret = POLLOUT; /* we can always handle more output */
+
+       poll_wait(NULL, &chan->wq, pt);
+
+       /* No buffer?  Try to get one. */
+       if (!chan->in_len)
+               chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);
+
+       if (chan->in_len)
+               ret |= POLLIN;
+
+       return ret;
+}
+
+static void p9_virtio_close(struct p9_trans *trans)
+{
+       struct virtio_chan *chan = trans->priv;
+
+       down(&virtio_9p_lock);
+       chan->inuse = false;
+       up(&virtio_9p_lock);
+
+       kfree(trans);
+}
+
+static bool p9_virtio_intr(struct virtqueue *q)
+{
+       struct virtio_chan *chan = q->vdev->priv;
+
+       P9_DPRINTK(P9_DEBUG_TRANS, "9p poll_wakeup: %p\n", &chan->wq);
+       wake_up_interruptible(&chan->wq);
+
+       return true;
+}
+
+static int p9_virtio_probe(struct virtio_device *dev)
+{
+       int err;
+       struct virtio_chan *chan;
+       int index;
+
+       down(&virtio_9p_lock);
+       index = chan_index++;
+       chan = &channels[index];
+       up(&virtio_9p_lock);
+
+       if (chan_index > MAX_9P_CHAN) {
+               printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
+               BUG();
+       }
+
+       chan->vdev = dev;
+
+       /* This is the scratch page we use to receive console input */
+       chan->inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!chan->inbuf) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Find the input queue. */
+       dev->priv = chan;
+       chan->in_vq = dev->config->find_vq(dev, p9_virtio_intr);
+       if (IS_ERR(chan->in_vq)) {
+               err = PTR_ERR(chan->in_vq);
+               goto free;
+       }
+
+       chan->out_vq = dev->config->find_vq(dev, NULL);
+       if (IS_ERR(chan->out_vq)) {
+               err = PTR_ERR(chan->out_vq);
+               goto free_in_vq;
+       }
+
+       init_waitqueue_head(&chan->wq);
+
+       /* Register the input buffer the first time. */
+       add_inbuf(chan);
+       chan->inuse = false;
+       chan->initialized = true;
+
+       return 0;
+
+free_in_vq:
+       dev->config->del_vq(chan->in_vq);
+free:
+       kfree(chan->inbuf);
+fail:
+       down(&virtio_9p_lock);
+       chan_index--;
+       up(&virtio_9p_lock);
+       return err;
+}
+
+/* This sets up a transport channel for 9p communication.  Right now
+ * we only match the first available channel, but eventually we couldlook up
+ * alternate channels by matching devname versus a virtio_config entry.
+ * We use a simple reference count mechanism to ensure that only a single
+ * mount has a channel open at a time. */
+static struct p9_trans *p9_virtio_create(const char *devname, char *args)
+{
+       struct p9_trans *trans;
+       int index = 0;
+       struct virtio_chan *chan = channels;
+
+       down(&virtio_9p_lock);
+       while (index < MAX_9P_CHAN) {
+               if (chan->initialized && !chan->inuse) {
+                       chan->inuse = true;
+                       break;
+               } else {
+                       index++;
+                       chan = &channels[index];
+               }
+       }
+       up(&virtio_9p_lock);
+
+       if (index >= MAX_9P_CHAN) {
+               printk(KERN_ERR "9p: virtio: couldn't find a free channel\n");
+               return NULL;
+       }
+
+       trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
+       if (!trans) {
+               printk(KERN_ERR "9p: couldn't allocate transport\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       trans->write = p9_virtio_write;
+       trans->read = p9_virtio_read;
+       trans->close = p9_virtio_close;
+       trans->poll = p9_virtio_poll;
+       trans->priv = chan;
+
+       return trans;
+}
+
+#define VIRTIO_ID_9P 9
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_9P, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+/* The standard "struct lguest_driver": */
+static struct virtio_driver p9_virtio_drv = {
+       .driver.name =  KBUILD_MODNAME,
+       .driver.owner = THIS_MODULE,
+       .id_table =     id_table,
+       .probe =        p9_virtio_probe,
+};
+
+static struct p9_trans_module p9_virtio_trans = {
+       .name = "virtio",
+       .create = p9_virtio_create,
+       .maxsize = PAGE_SIZE,
+       .def = 0,
+};
+
+/* The standard init function */
+static int __init p9_virtio_init(void)
+{
+       int count;
+
+       for (count = 0; count < MAX_9P_CHAN; count++)
+               channels[count].initialized = false;
+
+       v9fs_register_trans(&p9_virtio_trans);
+       return register_virtio_driver(&p9_virtio_drv);
+}
+
+module_init(p9_virtio_init);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
+MODULE_DESCRIPTION("Virtio 9p Transport");
+MODULE_LICENSE("GPL");
index 5fdfc9a..9483320 100644 (file)
@@ -78,11 +78,11 @@ void hci_acl_connect(struct hci_conn *conn)
 
        cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
        if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
-               cp.role_switch  = 0x01;
+               cp.role_switch = 0x01;
        else
-               cp.role_switch  = 0x00;
+               cp.role_switch = 0x00;
 
-       hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
+       hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
 }
 
 static void hci_acl_connect_cancel(struct hci_conn *conn)
@@ -95,8 +95,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn)
                return;
 
        bacpy(&cp.bdaddr, &conn->dst);
-       hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-                               OCF_CREATE_CONN_CANCEL, sizeof(cp), &cp);
+       hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
 }
 
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
@@ -109,8 +108,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
 
        cp.handle = cpu_to_le16(conn->handle);
        cp.reason = reason;
-       hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-                               OCF_DISCONNECT, sizeof(cp), &cp);
+       hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
 }
 
 void hci_add_sco(struct hci_conn *conn, __u16 handle)
@@ -126,7 +124,29 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
        cp.handle   = cpu_to_le16(handle);
        cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
 
-       hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp);
+       hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
+}
+
+void hci_setup_sync(struct hci_conn *conn, __u16 handle)
+{
+       struct hci_dev *hdev = conn->hdev;
+       struct hci_cp_setup_sync_conn cp;
+
+       BT_DBG("%p", conn);
+
+       conn->state = BT_CONNECT;
+       conn->out = 1;
+
+       cp.handle   = cpu_to_le16(handle);
+       cp.pkt_type = cpu_to_le16(hdev->esco_type);
+
+       cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
+       cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
+       cp.max_latency    = cpu_to_le16(0xffff);
+       cp.voice_setting  = cpu_to_le16(hdev->voice_setting);
+       cp.retrans_effort = 0xff;
+
+       hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
 }
 
 static void hci_conn_timeout(unsigned long arg)
@@ -143,7 +163,10 @@ static void hci_conn_timeout(unsigned long arg)
 
        switch (conn->state) {
        case BT_CONNECT:
-               hci_acl_connect_cancel(conn);
+               if (conn->type == ACL_LINK)
+                       hci_acl_connect_cancel(conn);
+               else
+                       hci_acl_disconn(conn, 0x13);
                break;
        case BT_CONNECTED:
                hci_acl_disconn(conn, 0x13);
@@ -330,8 +353,12 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
        hci_conn_hold(sco);
 
        if (acl->state == BT_CONNECTED &&
-                       (sco->state == BT_OPEN || sco->state == BT_CLOSED))
-               hci_add_sco(sco, acl->handle);
+                       (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
+               if (lmp_esco_capable(hdev))
+                       hci_setup_sync(sco, acl->handle);
+               else
+                       hci_add_sco(sco, acl->handle);
+       }
 
        return sco;
 }
@@ -348,7 +375,7 @@ int hci_conn_auth(struct hci_conn *conn)
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
                struct hci_cp_auth_requested cp;
                cp.handle = cpu_to_le16(conn->handle);
-               hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
        }
        return 0;
 }
@@ -369,7 +396,7 @@ int hci_conn_encrypt(struct hci_conn *conn)
                struct hci_cp_set_conn_encrypt cp;
                cp.handle  = cpu_to_le16(conn->handle);
                cp.encrypt = 1;
-               hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
        }
        return 0;
 }
@@ -383,7 +410,7 @@ int hci_conn_change_link_key(struct hci_conn *conn)
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
                struct hci_cp_change_conn_link_key cp;
                cp.handle = cpu_to_le16(conn->handle);
-               hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
        }
        return 0;
 }
@@ -401,7 +428,7 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
                struct hci_cp_switch_role cp;
                bacpy(&cp.bdaddr, &conn->dst);
                cp.role = role;
-               hci_send_cmd(conn->hdev, OGF_LINK_POLICY, OCF_SWITCH_ROLE, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
        }
        return 0;
 }
@@ -423,8 +450,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn)
        if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
                struct hci_cp_exit_sniff_mode cp;
                cp.handle = cpu_to_le16(conn->handle);
-               hci_send_cmd(hdev, OGF_LINK_POLICY,
-                               OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
        }
 
 timer:
@@ -455,8 +481,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
                cp.max_latency        = cpu_to_le16(0);
                cp.min_remote_timeout = cpu_to_le16(0);
                cp.min_local_timeout  = cpu_to_le16(0);
-               hci_send_cmd(hdev, OGF_LINK_POLICY,
-                               OCF_SNIFF_SUBRATE, sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
        }
 
        if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
@@ -466,8 +491,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
                cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
                cp.attempt      = cpu_to_le16(4);
                cp.timeout      = cpu_to_le16(1);
-               hci_send_cmd(hdev, OGF_LINK_POLICY,
-                               OCF_SNIFF_MODE, sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
        }
 }
 
@@ -493,6 +517,22 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
        }
 }
 
+/* Check pending connect attempts */
+void hci_conn_check_pending(struct hci_dev *hdev)
+{
+       struct hci_conn *conn;
+
+       BT_DBG("hdev %s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
+       if (conn)
+               hci_acl_connect(conn);
+
+       hci_dev_unlock(hdev);
+}
+
 int hci_get_conn_list(void __user *arg)
 {
        struct hci_conn_list_req req, *cl;
index 18e3afc..372b0d3 100644 (file)
@@ -176,7 +176,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %ld", hdev->name, opt);
 
        /* Reset device */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 }
 
 static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
@@ -202,16 +202,16 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 
        /* Reset */
        if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
-                       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+                       hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 
        /* Read Local Supported Features */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
 
        /* Read Local Version */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
 
        /* Read Buffer Size (ACL mtu, max pkt, etc.) */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
 
 #if 0
        /* Host buffer size */
@@ -221,29 +221,35 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
                cp.sco_mtu = HCI_MAX_SCO_SIZE;
                cp.acl_max_pkt = cpu_to_le16(0xffff);
                cp.sco_max_pkt = cpu_to_le16(0xffff);
-               hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE, sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
        }
 #endif
 
        /* Read BD Address */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
+
+       /* Read Class of Device */
+       hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
+
+       /* Read Local Name */
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
 
        /* Read Voice Setting */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
 
        /* Optional initialization */
 
        /* Clear Event Filters */
        flt_type = HCI_FLT_CLEAR_ALL;
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &flt_type);
+       hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
 
        /* Page timeout ~20 secs */
        param = cpu_to_le16(0x8000);
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_PG_TIMEOUT, 2, &param);
+       hci_send_cmd(hdev, HCI_OP_WRITE_PG_TIMEOUT, 2, &param);
 
        /* Connection accept timeout ~20 secs */
        param = cpu_to_le16(0x7d00);
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_CA_TIMEOUT, 2, &param);
+       hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
 }
 
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
@@ -253,7 +259,7 @@ static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %x", hdev->name, scan);
 
        /* Inquiry and Page scans */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
+       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
 }
 
 static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
@@ -263,7 +269,7 @@ static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %x", hdev->name, auth);
 
        /* Authentication */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
+       hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
 }
 
 static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
@@ -273,7 +279,7 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %x", hdev->name, encrypt);
 
        /* Authentication */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
+       hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
 }
 
 /* Get HCI device by index.
@@ -384,7 +390,7 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
        memcpy(&cp.lap, &ir->lap, 3);
        cp.length  = ir->length;
        cp.num_rsp = ir->num_rsp;
-       hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, sizeof(cp), &cp);
+       hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
 }
 
 int hci_inquiry(void __user *arg)
@@ -1111,13 +1117,13 @@ static int hci_send_frame(struct sk_buff *skb)
 }
 
 /* Send HCI command */
-int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
 {
        int len = HCI_COMMAND_HDR_SIZE + plen;
        struct hci_command_hdr *hdr;
        struct sk_buff *skb;
 
-       BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
+       BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);
 
        skb = bt_skb_alloc(len, GFP_ATOMIC);
        if (!skb) {
@@ -1126,7 +1132,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
        }
 
        hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
-       hdr->opcode = cpu_to_le16(hci_opcode_pack(ogf, ocf));
+       hdr->opcode = cpu_to_le16(opcode);
        hdr->plen   = plen;
 
        if (plen)
@@ -1143,7 +1149,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
 }
 
 /* Get data from the previously sent command */
-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
 {
        struct hci_command_hdr *hdr;
 
@@ -1152,10 +1158,10 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
 
        hdr = (void *) hdev->sent_cmd->data;
 
-       if (hdr->opcode != cpu_to_le16(hci_opcode_pack(ogf, ocf)))
+       if (hdr->opcode != cpu_to_le16(opcode))
                return NULL;
 
-       BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
+       BT_DBG("%s opcode 0x%x", hdev->name, opcode);
 
        return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
 }
@@ -1355,6 +1361,26 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
        }
 }
 
+static inline void hci_sched_esco(struct hci_dev *hdev)
+{
+       struct hci_conn *conn;
+       struct sk_buff *skb;
+       int quote;
+
+       BT_DBG("%s", hdev->name);
+
+       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
+               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+                       BT_DBG("skb %p len %d", skb, skb->len);
+                       hci_send_frame(skb);
+
+                       conn->sent++;
+                       if (conn->sent == ~0)
+                               conn->sent = 0;
+               }
+       }
+}
+
 static void hci_tx_task(unsigned long arg)
 {
        struct hci_dev *hdev = (struct hci_dev *) arg;
@@ -1370,6 +1396,8 @@ static void hci_tx_task(unsigned long arg)
 
        hci_sched_sco(hdev);
 
+       hci_sched_esco(hdev);
+
        /* Send next queued raw (unknown type) packet */
        while ((skb = skb_dequeue(&hdev->raw_q)))
                hci_send_frame(skb);
index 4baea1e..46df2e4 100644 (file)
 
 /* Handle HCI Event packets */
 
-/* Command Complete OGF LINK_CTL  */
-static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       __u8 status;
-       struct hci_conn *pend;
+       __u8 status = *((__u8 *) skb->data);
 
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       switch (ocf) {
-       case OCF_INQUIRY_CANCEL:
-       case OCF_EXIT_PERIODIC_INQ:
-               status = *((__u8 *) skb->data);
+       if (status)
+               return;
 
-               if (status) {
-                       BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
-               } else {
-                       clear_bit(HCI_INQUIRY, &hdev->flags);
-                       hci_req_complete(hdev, status);
-               }
+       clear_bit(HCI_INQUIRY, &hdev->flags);
 
-               hci_dev_lock(hdev);
+       hci_req_complete(hdev, status);
+
+       hci_conn_check_pending(hdev);
+}
 
-               pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
-               if (pend)
-                       hci_acl_connect(pend);
+static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
 
-               hci_dev_unlock(hdev);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-               break;
+       if (status)
+               return;
 
-       default:
-               BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
-               break;
+       clear_bit(HCI_INQUIRY, &hdev->flags);
+
+       hci_conn_check_pending(hdev);
+}
+
+static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_role_discovery *rp = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (conn) {
+               if (rp->role)
+                       conn->link_mode &= ~HCI_LM_MASTER;
+               else
+                       conn->link_mode |= HCI_LM_MASTER;
        }
+
+       hci_dev_unlock(hdev);
 }
 
-/* Command Complete OGF LINK_POLICY  */
-static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 {
+       struct hci_rp_write_link_policy *rp = (void *) skb->data;
        struct hci_conn *conn;
-       struct hci_rp_role_discovery *rd;
-       struct hci_rp_write_link_policy *lp;
        void *sent;
 
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-       switch (ocf) {
-       case OCF_ROLE_DISCOVERY:
-               rd = (void *) skb->data;
+       if (rp->status)
+               return;
 
-               if (rd->status)
-                       break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
+       if (!sent)
+               return;
 
-               hci_dev_lock(hdev);
+       hci_dev_lock(hdev);
 
-               conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle));
-               if (conn) {
-                       if (rd->role)
-                               conn->link_mode &= ~HCI_LM_MASTER;
-                       else
-                               conn->link_mode |= HCI_LM_MASTER;
-               }
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (conn) {
+               __le16 policy = get_unaligned((__le16 *) (sent + 2));
+               conn->link_policy = __le16_to_cpu(policy);
+       }
 
-               hci_dev_unlock(hdev);
-               break;
+       hci_dev_unlock(hdev);
+}
 
-       case OCF_WRITE_LINK_POLICY:
-               sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY);
-               if (!sent)
-                       break;
+static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
 
-               lp = (struct hci_rp_write_link_policy *) skb->data;
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-               if (lp->status)
-                       break;
+       hci_req_complete(hdev, status);
+}
 
-               hci_dev_lock(hdev);
+static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
 
-               conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle));
-               if (conn) {
-                       __le16 policy = get_unaligned((__le16 *) (sent + 2));
-                       conn->link_policy = __le16_to_cpu(policy);
-               }
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-               hci_dev_unlock(hdev);
-               break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
+       if (!sent)
+               return;
 
-       default:
-               BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x",
-                               hdev->name, ocf);
-               break;
+       if (!status)
+               memcpy(hdev->dev_name, sent, 248);
+}
+
+static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_local_name *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       memcpy(hdev->dev_name, rp->name, 248);
+}
+
+static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
+
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE);
+       if (!sent)
+               return;
+
+       if (!status) {
+               __u8 param = *((__u8 *) sent);
+
+               if (param == AUTH_ENABLED)
+                       set_bit(HCI_AUTH, &hdev->flags);
+               else
+                       clear_bit(HCI_AUTH, &hdev->flags);
        }
+
+       hci_req_complete(hdev, status);
 }
 
-/* Command Complete OGF HOST_CTL  */
-static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       __u8 status, param;
-       __u16 setting;
-       struct hci_rp_read_voice_setting *vs;
+       __u8 status = *((__u8 *) skb->data);
        void *sent;
 
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       switch (ocf) {
-       case OCF_RESET:
-               status = *((__u8 *) skb->data);
-               hci_req_complete(hdev, status);
-               break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE);
+       if (!sent)
+               return;
 
-       case OCF_SET_EVENT_FLT:
-               status = *((__u8 *) skb->data);
-               if (status) {
-                       BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
-               } else {
-                       BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name);
-               }
-               break;
+       if (!status) {
+               __u8 param = *((__u8 *) sent);
+
+               if (param)
+                       set_bit(HCI_ENCRYPT, &hdev->flags);
+               else
+                       clear_bit(HCI_ENCRYPT, &hdev->flags);
+       }
 
-       case OCF_WRITE_AUTH_ENABLE:
-               sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
-               if (!sent)
-                       break;
+       hci_req_complete(hdev, status);
+}
 
-               status = *((__u8 *) skb->data);
-               param  = *((__u8 *) sent);
+static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
 
-               if (!status) {
-                       if (param == AUTH_ENABLED)
-                               set_bit(HCI_AUTH, &hdev->flags);
-                       else
-                               clear_bit(HCI_AUTH, &hdev->flags);
-               }
-               hci_req_complete(hdev, status);
-               break;
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       case OCF_WRITE_ENCRYPT_MODE:
-               sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
-               if (!sent)
-                       break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE);
+       if (!sent)
+               return;
 
-               status = *((__u8 *) skb->data);
-               param  = *((__u8 *) sent);
+       if (!status) {
+               __u8 param = *((__u8 *) sent);
 
-               if (!status) {
-                       if (param)
-                               set_bit(HCI_ENCRYPT, &hdev->flags);
-                       else
-                               clear_bit(HCI_ENCRYPT, &hdev->flags);
-               }
-               hci_req_complete(hdev, status);
-               break;
+               clear_bit(HCI_PSCAN, &hdev->flags);
+               clear_bit(HCI_ISCAN, &hdev->flags);
 
-       case OCF_WRITE_CA_TIMEOUT:
-               status = *((__u8 *) skb->data);
-               if (status) {
-                       BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
-               } else {
-                       BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
-               }
-               break;
+               if (param & SCAN_INQUIRY)
+                       set_bit(HCI_ISCAN, &hdev->flags);
 
-       case OCF_WRITE_PG_TIMEOUT:
-               status = *((__u8 *) skb->data);
-               if (status) {
-                       BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
-               } else {
-                       BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
-               }
-               break;
+               if (param & SCAN_PAGE)
+                       set_bit(HCI_PSCAN, &hdev->flags);
+       }
 
-       case OCF_WRITE_SCAN_ENABLE:
-               sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
-               if (!sent)
-                       break;
+       hci_req_complete(hdev, status);
+}
 
-               status = *((__u8 *) skb->data);
-               param  = *((__u8 *) sent);
+static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
 
-               BT_DBG("param 0x%x", param);
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               if (!status) {
-                       clear_bit(HCI_PSCAN, &hdev->flags);
-                       clear_bit(HCI_ISCAN, &hdev->flags);
-                       if (param & SCAN_INQUIRY)
-                               set_bit(HCI_ISCAN, &hdev->flags);
+       if (rp->status)
+               return;
 
-                       if (param & SCAN_PAGE)
-                               set_bit(HCI_PSCAN, &hdev->flags);
-               }
-               hci_req_complete(hdev, status);
-               break;
+       memcpy(hdev->dev_class, rp->dev_class, 3);
 
-       case OCF_READ_VOICE_SETTING:
-               vs = (struct hci_rp_read_voice_setting *) skb->data;
+       BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
+               hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+}
 
-               if (vs->status) {
-                       BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vs->status);
-                       break;
-               }
+static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
 
-               setting = __le16_to_cpu(vs->voice_setting);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-               if (hdev->voice_setting != setting ) {
-                       hdev->voice_setting = setting;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
+       if (!sent)
+               return;
 
-                       BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
+       if (!status)
+               memcpy(hdev->dev_class, sent, 3);
+}
 
-                       if (hdev->notify) {
-                               tasklet_disable(&hdev->tx_task);
-                               hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-                               tasklet_enable(&hdev->tx_task);
-                       }
-               }
-               break;
+static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_voice_setting *rp = (void *) skb->data;
+       __u16 setting;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       setting = __le16_to_cpu(rp->voice_setting);
+
+       if (hdev->voice_setting == setting )
+               return;
+
+       hdev->voice_setting = setting;
+
+       BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
+
+       if (hdev->notify) {
+               tasklet_disable(&hdev->tx_task);
+               hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
+               tasklet_enable(&hdev->tx_task);
+       }
+}
+
+static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
+
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       case OCF_WRITE_VOICE_SETTING:
-               sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING);
-               if (!sent)
-                       break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
+       if (!sent)
+               return;
 
-               status = *((__u8 *) skb->data);
-               setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
+       if (!status) {
+               __u16 setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
 
-               if (!status && hdev->voice_setting != setting) {
+               if (hdev->voice_setting != setting) {
                        hdev->voice_setting = setting;
 
-                       BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
+                       BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
 
                        if (hdev->notify) {
                                tasklet_disable(&hdev->tx_task);
@@ -287,143 +326,153 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
                                tasklet_enable(&hdev->tx_task);
                        }
                }
-               hci_req_complete(hdev, status);
-               break;
-
-       case OCF_HOST_BUFFER_SIZE:
-               status = *((__u8 *) skb->data);
-               if (status) {
-                       BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
-                       hci_req_complete(hdev, status);
-               }
-               break;
-
-       default:
-               BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
-               break;
        }
 }
 
-/* Command Complete OGF INFO_PARAM  */
-static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_rp_read_loc_version *lv;
-       struct hci_rp_read_local_features *lf;
-       struct hci_rp_read_buffer_size *bs;
-       struct hci_rp_read_bd_addr *ba;
+       __u8 status = *((__u8 *) skb->data);
 
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       switch (ocf) {
-       case OCF_READ_LOCAL_VERSION:
-               lv = (struct hci_rp_read_loc_version *) skb->data;
+       hci_req_complete(hdev, status);
+}
 
-               if (lv->status) {
-                       BT_DBG("%s READ_LOCAL_VERSION failed %d", hdev->name, lf->status);
-                       break;
-               }
+static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_local_version *rp = (void *) skb->data;
 
-               hdev->hci_ver = lv->hci_ver;
-               hdev->hci_rev = btohs(lv->hci_rev);
-               hdev->manufacturer = btohs(lv->manufacturer);
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               BT_DBG("%s: manufacturer %d hci_ver %d hci_rev %d", hdev->name,
-                               hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
+       if (rp->status)
+               return;
 
-               break;
+       hdev->hci_ver = rp->hci_ver;
+       hdev->hci_rev = btohs(rp->hci_rev);
+       hdev->manufacturer = btohs(rp->manufacturer);
 
-       case OCF_READ_LOCAL_FEATURES:
-               lf = (struct hci_rp_read_local_features *) skb->data;
+       BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
+                                       hdev->manufacturer,
+                                       hdev->hci_ver, hdev->hci_rev);
+}
 
-               if (lf->status) {
-                       BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
-                       break;
-               }
+static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_local_commands *rp = (void *) skb->data;
 
-               memcpy(hdev->features, lf->features, sizeof(hdev->features));
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               /* Adjust default settings according to features
-                * supported by device. */
-               if (hdev->features[0] & LMP_3SLOT)
-                       hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
+       if (rp->status)
+               return;
 
-               if (hdev->features[0] & LMP_5SLOT)
-                       hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
+       memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
+}
 
-               if (hdev->features[1] & LMP_HV2) {
-                       hdev->pkt_type  |= (HCI_HV2);
-                       hdev->esco_type |= (ESCO_HV2);
-               }
+static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_local_features *rp = (void *) skb->data;
 
-               if (hdev->features[1] & LMP_HV3) {
-                       hdev->pkt_type  |= (HCI_HV3);
-                       hdev->esco_type |= (ESCO_HV3);
-               }
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               if (hdev->features[3] & LMP_ESCO)
-                       hdev->esco_type |= (ESCO_EV3);
+       if (rp->status)
+               return;
 
-               if (hdev->features[4] & LMP_EV4)
-                       hdev->esco_type |= (ESCO_EV4);
+       memcpy(hdev->features, rp->features, 8);
 
-               if (hdev->features[4] & LMP_EV5)
-                       hdev->esco_type |= (ESCO_EV5);
+       /* Adjust default settings according to features
+        * supported by device. */
 
-               BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name,
-                               lf->features[0], lf->features[1], lf->features[2]);
+       if (hdev->features[0] & LMP_3SLOT)
+               hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
 
-               break;
+       if (hdev->features[0] & LMP_5SLOT)
+               hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
 
-       case OCF_READ_BUFFER_SIZE:
-               bs = (struct hci_rp_read_buffer_size *) skb->data;
+       if (hdev->features[1] & LMP_HV2) {
+               hdev->pkt_type  |= (HCI_HV2);
+               hdev->esco_type |= (ESCO_HV2);
+       }
 
-               if (bs->status) {
-                       BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
-                       hci_req_complete(hdev, bs->status);
-                       break;
-               }
+       if (hdev->features[1] & LMP_HV3) {
+               hdev->pkt_type  |= (HCI_HV3);
+               hdev->esco_type |= (ESCO_HV3);
+       }
 
-               hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
-               hdev->sco_mtu  = bs->sco_mtu;
-               hdev->acl_pkts = __le16_to_cpu(bs->acl_max_pkt);
-               hdev->sco_pkts = __le16_to_cpu(bs->sco_max_pkt);
+       if (hdev->features[3] & LMP_ESCO)
+               hdev->esco_type |= (ESCO_EV3);
 
-               if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
-                       hdev->sco_mtu  = 64;
-                       hdev->sco_pkts = 8;
-               }
+       if (hdev->features[4] & LMP_EV4)
+               hdev->esco_type |= (ESCO_EV4);
 
-               hdev->acl_cnt = hdev->acl_pkts;
-               hdev->sco_cnt = hdev->sco_pkts;
+       if (hdev->features[4] & LMP_EV5)
+               hdev->esco_type |= (ESCO_EV5);
 
-               BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-                       hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
-               break;
+       BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
+                                       hdev->features[0], hdev->features[1],
+                                       hdev->features[2], hdev->features[3],
+                                       hdev->features[4], hdev->features[5],
+                                       hdev->features[6], hdev->features[7]);
+}
 
-       case OCF_READ_BD_ADDR:
-               ba = (struct hci_rp_read_bd_addr *) skb->data;
+static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_buffer_size *rp = (void *) skb->data;
 
-               if (!ba->status) {
-                       bacpy(&hdev->bdaddr, &ba->bdaddr);
-               } else {
-                       BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
-               }
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               hci_req_complete(hdev, ba->status);
-               break;
+       if (rp->status)
+               return;
 
-       default:
-               BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-               break;
+       hdev->acl_mtu  = __le16_to_cpu(rp->acl_mtu);
+       hdev->sco_mtu  = rp->sco_mtu;
+       hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
+       hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
+
+       if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
+               hdev->sco_mtu  = 64;
+               hdev->sco_pkts = 8;
        }
+
+       hdev->acl_cnt = hdev->acl_pkts;
+       hdev->sco_cnt = hdev->sco_pkts;
+
+       BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
+                                       hdev->acl_mtu, hdev->acl_pkts,
+                                       hdev->sco_mtu, hdev->sco_pkts);
+}
+
+static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_bd_addr *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (!rp->status)
+               bacpy(&hdev->bdaddr, &rp->bdaddr);
+
+       hci_req_complete(hdev, rp->status);
+}
+
+static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
+{
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       if (status) {
+               hci_req_complete(hdev, status);
+
+               hci_conn_check_pending(hdev);
+       } else
+               set_bit(HCI_INQUIRY, &hdev->flags);
 }
 
-/* Command Status OGF LINK_CTL  */
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 {
+       struct hci_cp_create_conn *cp;
        struct hci_conn *conn;
-       struct hci_cp_create_conn *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
 
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_CONN);
        if (!cp)
                return;
 
@@ -431,8 +480,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
 
-       BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name,
-                       status, batostr(&cp->bdaddr), conn);
+       BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->bdaddr), conn);
 
        if (status) {
                if (conn && conn->state == BT_CONNECT) {
@@ -457,234 +505,138 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
        hci_dev_unlock(hdev);
 }
 
-static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
 {
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-
-       switch (ocf) {
-       case OCF_CREATE_CONN:
-               hci_cs_create_conn(hdev, status);
-               break;
-
-       case OCF_ADD_SCO:
-               if (status) {
-                       struct hci_conn *acl, *sco;
-                       struct hci_cp_add_sco *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_ADD_SCO);
-                       __u16 handle;
+       struct hci_cp_add_sco *cp;
+       struct hci_conn *acl, *sco;
+       __u16 handle;
 
-                       if (!cp)
-                               break;
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-                       handle = __le16_to_cpu(cp->handle);
-
-                       BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
+       if (!status)
+               return;
 
-                       hci_dev_lock(hdev);
+       cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO);
+       if (!cp)
+               return;
 
-                       acl = hci_conn_hash_lookup_handle(hdev, handle);
-                       if (acl && (sco = acl->link)) {
-                               sco->state = BT_CLOSED;
+       handle = __le16_to_cpu(cp->handle);
 
-                               hci_proto_connect_cfm(sco, status);
-                               hci_conn_del(sco);
-                       }
+       BT_DBG("%s handle %d", hdev->name, handle);
 
-                       hci_dev_unlock(hdev);
-               }
-               break;
+       hci_dev_lock(hdev);
 
-       case OCF_INQUIRY:
-               if (status) {
-                       BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status);
-                       hci_req_complete(hdev, status);
-               } else {
-                       set_bit(HCI_INQUIRY, &hdev->flags);
-               }
-               break;
+       acl = hci_conn_hash_lookup_handle(hdev, handle);
+       if (acl && (sco = acl->link)) {
+               sco->state = BT_CLOSED;
 
-       default:
-               BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d",
-                       hdev->name, ocf, status);
-               break;
+               hci_proto_connect_cfm(sco, status);
+               hci_conn_del(sco);
        }
+
+       hci_dev_unlock(hdev);
 }
 
-/* Command Status OGF LINK_POLICY */
-static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
+static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 {
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-
-       switch (ocf) {
-       case OCF_SNIFF_MODE:
-               if (status) {
-                       struct hci_conn *conn;
-                       struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE);
-
-                       if (!cp)
-                               break;
+       BT_DBG("%s status 0x%x", hdev->name, status);
+}
 
-                       hci_dev_lock(hdev);
+static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
+{
+       struct hci_cp_setup_sync_conn *cp;
+       struct hci_conn *acl, *sco;
+       __u16 handle;
 
-                       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
-                       if (conn) {
-                               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
-                       }
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-                       hci_dev_unlock(hdev);
-               }
-               break;
+       if (!status)
+               return;
 
-       case OCF_EXIT_SNIFF_MODE:
-               if (status) {
-                       struct hci_conn *conn;
-                       struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE);
+       cp = hci_sent_cmd_data(hdev, HCI_OP_SETUP_SYNC_CONN);
+       if (!cp)
+               return;
 
-                       if (!cp)
-                               break;
+       handle = __le16_to_cpu(cp->handle);
 
-                       hci_dev_lock(hdev);
+       BT_DBG("%s handle %d", hdev->name, handle);
 
-                       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
-                       if (conn) {
-                               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
-                       }
+       hci_dev_lock(hdev);
 
-                       hci_dev_unlock(hdev);
-               }
-               break;
+       acl = hci_conn_hash_lookup_handle(hdev, handle);
+       if (acl && (sco = acl->link)) {
+               sco->state = BT_CLOSED;
 
-       default:
-               BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf);
-               break;
+               hci_proto_connect_cfm(sco, status);
+               hci_conn_del(sco);
        }
+
+       hci_dev_unlock(hdev);
 }
 
-/* Command Status OGF HOST_CTL */
-static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
 {
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       struct hci_cp_sniff_mode *cp;
+       struct hci_conn *conn;
 
-       switch (ocf) {
-       default:
-               BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
-               break;
-       }
-}
-
-/* Command Status OGF INFO_PARAM  */
-static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
-{
-       BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
-
-       switch (ocf) {
-       default:
-               BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-               break;
-       }
-}
-
-/* Inquiry Complete */
-static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       __u8 status = *((__u8 *) skb->data);
-       struct hci_conn *pend;
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       BT_DBG("%s status %d", hdev->name, status);
+       if (!status)
+               return;
 
-       clear_bit(HCI_INQUIRY, &hdev->flags);
-       hci_req_complete(hdev, status);
+       cp = hci_sent_cmd_data(hdev, HCI_OP_SNIFF_MODE);
+       if (!cp)
+               return;
 
        hci_dev_lock(hdev);
 
-       pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
-       if (pend)
-               hci_acl_connect(pend);
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (conn)
+               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
 
        hci_dev_unlock(hdev);
 }
 
-/* Inquiry Result */
-static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
 {
-       struct inquiry_data data;
-       struct inquiry_info *info = (struct inquiry_info *) (skb->data + 1);
-       int num_rsp = *((__u8 *) skb->data);
+       struct hci_cp_exit_sniff_mode *cp;
+       struct hci_conn *conn;
 
-       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       if (!num_rsp)
+       if (!status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_EXIT_SNIFF_MODE);
+       if (!cp)
                return;
 
        hci_dev_lock(hdev);
 
-       for (; num_rsp; num_rsp--) {
-               bacpy(&data.bdaddr, &info->bdaddr);
-               data.pscan_rep_mode     = info->pscan_rep_mode;
-               data.pscan_period_mode  = info->pscan_period_mode;
-               data.pscan_mode         = info->pscan_mode;
-               memcpy(data.dev_class, info->dev_class, 3);
-               data.clock_offset       = info->clock_offset;
-               data.rssi               = 0x00;
-               info++;
-               hci_inquiry_cache_update(hdev, &data);
-       }
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (conn)
+               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
 
        hci_dev_unlock(hdev);
 }
 
-/* Inquiry Result With RSSI */
-static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct inquiry_data data;
-       int num_rsp = *((__u8 *) skb->data);
-
-       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
-       if (!num_rsp)
-               return;
-
-       hci_dev_lock(hdev);
+       __u8 status = *((__u8 *) skb->data);
 
-       if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
-               struct inquiry_info_with_rssi_and_pscan_mode *info =
-                       (struct inquiry_info_with_rssi_and_pscan_mode *) (skb->data + 1);
+       BT_DBG("%s status %d", hdev->name, status);
 
-               for (; num_rsp; num_rsp--) {
-                       bacpy(&data.bdaddr, &info->bdaddr);
-                       data.pscan_rep_mode     = info->pscan_rep_mode;
-                       data.pscan_period_mode  = info->pscan_period_mode;
-                       data.pscan_mode         = info->pscan_mode;
-                       memcpy(data.dev_class, info->dev_class, 3);
-                       data.clock_offset       = info->clock_offset;
-                       data.rssi               = info->rssi;
-                       info++;
-                       hci_inquiry_cache_update(hdev, &data);
-               }
-       } else {
-               struct inquiry_info_with_rssi *info =
-                       (struct inquiry_info_with_rssi *) (skb->data + 1);
+       clear_bit(HCI_INQUIRY, &hdev->flags);
 
-               for (; num_rsp; num_rsp--) {
-                       bacpy(&data.bdaddr, &info->bdaddr);
-                       data.pscan_rep_mode     = info->pscan_rep_mode;
-                       data.pscan_period_mode  = info->pscan_period_mode;
-                       data.pscan_mode         = 0x00;
-                       memcpy(data.dev_class, info->dev_class, 3);
-                       data.clock_offset       = info->clock_offset;
-                       data.rssi               = info->rssi;
-                       info++;
-                       hci_inquiry_cache_update(hdev, &data);
-               }
-       }
+       hci_req_complete(hdev, status);
 
-       hci_dev_unlock(hdev);
+       hci_conn_check_pending(hdev);
 }
 
-/* Extended Inquiry Result */
-static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct inquiry_data data;
-       struct extended_inquiry_info *info = (struct extended_inquiry_info *) (skb->data + 1);
+       struct inquiry_info *info = (void *) (skb->data + 1);
        int num_rsp = *((__u8 *) skb->data);
 
        BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
@@ -696,12 +648,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
 
        for (; num_rsp; num_rsp--) {
                bacpy(&data.bdaddr, &info->bdaddr);
-               data.pscan_rep_mode     = info->pscan_rep_mode;
-               data.pscan_period_mode  = info->pscan_period_mode;
-               data.pscan_mode         = 0x00;
+               data.pscan_rep_mode     = info->pscan_rep_mode;
+               data.pscan_period_mode  = info->pscan_period_mode;
+               data.pscan_mode         = info->pscan_mode;
                memcpy(data.dev_class, info->dev_class, 3);
-               data.clock_offset       = info->clock_offset;
-               data.rssi               = info->rssi;
+               data.clock_offset       = info->clock_offset;
+               data.rssi               = 0x00;
                info++;
                hci_inquiry_cache_update(hdev, &data);
        }
@@ -709,70 +661,18 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
        hci_dev_unlock(hdev);
 }
 
-/* Connect Request */
-static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       struct hci_ev_conn_request *ev = (struct hci_ev_conn_request *) skb->data;
-       int mask = hdev->link_mode;
-
-       BT_DBG("%s Connection request: %s type 0x%x", hdev->name,
-                       batostr(&ev->bdaddr), ev->link_type);
-
-       mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
-
-       if (mask & HCI_LM_ACCEPT) {
-               /* Connection accepted */
-               struct hci_conn *conn;
-               struct hci_cp_accept_conn_req cp;
-
-               hci_dev_lock(hdev);
-               conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
-               if (!conn) {
-                       if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
-                               BT_ERR("No memmory for new connection");
-                               hci_dev_unlock(hdev);
-                               return;
-                       }
-               }
-               memcpy(conn->dev_class, ev->dev_class, 3);
-               conn->state = BT_CONNECT;
-               hci_dev_unlock(hdev);
-
-               bacpy(&cp.bdaddr, &ev->bdaddr);
-
-               if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
-                       cp.role = 0x00; /* Become master */
-               else
-                       cp.role = 0x01; /* Remain slave */
-
-               hci_send_cmd(hdev, OGF_LINK_CTL,
-                               OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp);
-       } else {
-               /* Connection rejected */
-               struct hci_cp_reject_conn_req cp;
-
-               bacpy(&cp.bdaddr, &ev->bdaddr);
-               cp.reason = 0x0f;
-               hci_send_cmd(hdev, OGF_LINK_CTL,
-                               OCF_REJECT_CONN_REQ, sizeof(cp), &cp);
-       }
-}
-
-/* Connect Complete */
 static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
-       struct hci_conn *conn, *pend;
+       struct hci_ev_conn_complete *ev = (void *) skb->data;
+       struct hci_conn *conn;
 
        BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
-       if (!conn) {
-               hci_dev_unlock(hdev);
-               return;
-       }
+       if (!conn)
+               goto unlock;
 
        if (!ev->status) {
                conn->handle = __le16_to_cpu(ev->handle);
@@ -788,8 +688,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                if (conn->type == ACL_LINK) {
                        struct hci_cp_read_remote_features cp;
                        cp.handle = ev->handle;
-                       hci_send_cmd(hdev, OGF_LINK_CTL,
-                               OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp);
                }
 
                /* Set link policy */
@@ -797,8 +696,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        struct hci_cp_write_link_policy cp;
                        cp.handle = ev->handle;
                        cp.policy = cpu_to_le16(hdev->link_policy);
-                       hci_send_cmd(hdev, OGF_LINK_POLICY,
-                               OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp);
                }
 
                /* Set packet type for incoming connection */
@@ -809,8 +707,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                                cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
                                cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
 
-                       hci_send_cmd(hdev, OGF_LINK_CTL,
-                               OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
                } else {
                        /* Update disconnect timer */
                        hci_conn_hold(conn);
@@ -822,9 +719,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        if (conn->type == ACL_LINK) {
                struct hci_conn *sco = conn->link;
                if (sco) {
-                       if (!ev->status)
-                               hci_add_sco(sco, conn->handle);
-                       else {
+                       if (!ev->status) {
+                               if (lmp_esco_capable(hdev))
+                                       hci_setup_sync(sco, conn->handle);
+                               else
+                                       hci_add_sco(sco, conn->handle);
+                       } else {
                                hci_proto_connect_cfm(sco, ev->status);
                                hci_conn_del(sco);
                        }
@@ -835,136 +735,104 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        if (ev->status)
                hci_conn_del(conn);
 
-       pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
-       if (pend)
-               hci_acl_connect(pend);
-
+unlock:
        hci_dev_unlock(hdev);
-}
-
-/* Disconnect Complete */
-static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data;
-       struct hci_conn *conn;
-
-       BT_DBG("%s status %d", hdev->name, ev->status);
 
-       if (ev->status)
-               return;
-
-       hci_dev_lock(hdev);
-
-       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-       if (conn) {
-               conn->state = BT_CLOSED;
-               hci_proto_disconn_ind(conn, ev->reason);
-               hci_conn_del(conn);
-       }
-
-       hci_dev_unlock(hdev);
+       hci_conn_check_pending(hdev);
 }
 
-/* Number of completed packets */
-static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_num_comp_pkts *ev = (struct hci_ev_num_comp_pkts *) skb->data;
-       __le16 *ptr;
-       int i;
-
-       skb_pull(skb, sizeof(*ev));
-
-       BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
+       struct hci_ev_conn_request *ev = (void *) skb->data;
+       int mask = hdev->link_mode;
 
-       if (skb->len < ev->num_hndl * 4) {
-               BT_DBG("%s bad parameters", hdev->name);
-               return;
-       }
+       BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
+                                       batostr(&ev->bdaddr), ev->link_type);
 
-       tasklet_disable(&hdev->tx_task);
+       mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
 
-       for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
+       if (mask & HCI_LM_ACCEPT) {
+               /* Connection accepted */
                struct hci_conn *conn;
-               __u16  handle, count;
 
-               handle = __le16_to_cpu(get_unaligned(ptr++));
-               count  = __le16_to_cpu(get_unaligned(ptr++));
-
-               conn = hci_conn_hash_lookup_handle(hdev, handle);
-               if (conn) {
-                       conn->sent -= count;
+               hci_dev_lock(hdev);
 
-                       if (conn->type == ACL_LINK) {
-                               if ((hdev->acl_cnt += count) > hdev->acl_pkts)
-                                       hdev->acl_cnt = hdev->acl_pkts;
-                       } else {
-                               if ((hdev->sco_cnt += count) > hdev->sco_pkts)
-                                       hdev->sco_cnt = hdev->sco_pkts;
+               conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
+               if (!conn) {
+                       if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
+                               BT_ERR("No memmory for new connection");
+                               hci_dev_unlock(hdev);
+                               return;
                        }
                }
-       }
-       hci_sched_tx(hdev);
 
-       tasklet_enable(&hdev->tx_task);
-}
+               memcpy(conn->dev_class, ev->dev_class, 3);
+               conn->state = BT_CONNECT;
 
-/* Role Change */
-static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data;
-       struct hci_conn *conn;
+               hci_dev_unlock(hdev);
 
-       BT_DBG("%s status %d", hdev->name, ev->status);
+               if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) {
+                       struct hci_cp_accept_conn_req cp;
 
-       hci_dev_lock(hdev);
+                       bacpy(&cp.bdaddr, &ev->bdaddr);
 
-       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-       if (conn) {
-               if (!ev->status) {
-                       if (ev->role)
-                               conn->link_mode &= ~HCI_LM_MASTER;
+                       if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
+                               cp.role = 0x00; /* Become master */
                        else
-                               conn->link_mode |= HCI_LM_MASTER;
-               }
+                               cp.role = 0x01; /* Remain slave */
 
-               clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
+                       hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ,
+                                                       sizeof(cp), &cp);
+               } else {
+                       struct hci_cp_accept_sync_conn_req cp;
 
-               hci_role_switch_cfm(conn, ev->status, ev->role);
-       }
+                       bacpy(&cp.bdaddr, &ev->bdaddr);
+                       cp.pkt_type = cpu_to_le16(hdev->esco_type);
 
-       hci_dev_unlock(hdev);
+                       cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
+                       cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
+                       cp.max_latency    = cpu_to_le16(0xffff);
+                       cp.content_format = cpu_to_le16(hdev->voice_setting);
+                       cp.retrans_effort = 0xff;
+
+                       hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
+                                                       sizeof(cp), &cp);
+               }
+       } else {
+               /* Connection rejected */
+               struct hci_cp_reject_conn_req cp;
+
+               bacpy(&cp.bdaddr, &ev->bdaddr);
+               cp.reason = 0x0f;
+               hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
+       }
 }
 
-/* Mode Change */
-static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) skb->data;
+       struct hci_ev_disconn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
 
+       if (ev->status)
+               return;
+
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
-               conn->mode = ev->mode;
-               conn->interval = __le16_to_cpu(ev->interval);
-
-               if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
-                       if (conn->mode == HCI_CM_ACTIVE)
-                               conn->power_save = 1;
-                       else
-                               conn->power_save = 0;
-               }
+               conn->state = BT_CLOSED;
+               hci_proto_disconn_ind(conn, ev->reason);
+               hci_conn_del(conn);
        }
 
        hci_dev_unlock(hdev);
 }
 
-/* Authentication Complete */
 static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data;
+       struct hci_ev_auth_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -985,8 +853,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                                struct hci_cp_set_conn_encrypt cp;
                                cp.handle  = cpu_to_le16(conn->handle);
                                cp.encrypt = 1;
-                               hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-                                       OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
+                               hci_send_cmd(conn->hdev,
+                                       HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
                        } else {
                                clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
                                hci_encrypt_cfm(conn, ev->status, 0x00);
@@ -997,10 +865,16 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        hci_dev_unlock(hdev);
 }
 
-/* Encryption Change */
+static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+
+       hci_conn_check_pending(hdev);
+}
+
 static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data;
+       struct hci_ev_encrypt_change *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1024,10 +898,9 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
        hci_dev_unlock(hdev);
 }
 
-/* Change Connection Link Key Complete */
-static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data;
+       struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1047,25 +920,263 @@ static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, s
        hci_dev_unlock(hdev);
 }
 
-/* Pin Code Request*/
-static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-}
+       struct hci_ev_remote_features *ev = (void *) skb->data;
+       struct hci_conn *conn;
 
-/* Link Key Request */
-static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
+       BT_DBG("%s status %d", hdev->name, ev->status);
+
+       if (ev->status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+       if (conn)
+               memcpy(conn->features, ev->features, 8);
+
+       hci_dev_unlock(hdev);
 }
 
-/* Link Key Notification */
-static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+       BT_DBG("%s", hdev->name);
 }
 
-/* Remote Features */
-static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_remote_features *ev = (struct hci_ev_remote_features *) skb->data;
+       struct hci_ev_cmd_complete *ev = (void *) skb->data;
+       __u16 opcode;
+
+       skb_pull(skb, sizeof(*ev));
+
+       opcode = __le16_to_cpu(ev->opcode);
+
+       switch (opcode) {
+       case HCI_OP_INQUIRY_CANCEL:
+               hci_cc_inquiry_cancel(hdev, skb);
+               break;
+
+       case HCI_OP_EXIT_PERIODIC_INQ:
+               hci_cc_exit_periodic_inq(hdev, skb);
+               break;
+
+       case HCI_OP_REMOTE_NAME_REQ_CANCEL:
+               hci_cc_remote_name_req_cancel(hdev, skb);
+               break;
+
+       case HCI_OP_ROLE_DISCOVERY:
+               hci_cc_role_discovery(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_LINK_POLICY:
+               hci_cc_write_link_policy(hdev, skb);
+               break;
+
+       case HCI_OP_RESET:
+               hci_cc_reset(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_LOCAL_NAME:
+               hci_cc_write_local_name(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_NAME:
+               hci_cc_read_local_name(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_AUTH_ENABLE:
+               hci_cc_write_auth_enable(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_ENCRYPT_MODE:
+               hci_cc_write_encrypt_mode(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_SCAN_ENABLE:
+               hci_cc_write_scan_enable(hdev, skb);
+               break;
+
+       case HCI_OP_READ_CLASS_OF_DEV:
+               hci_cc_read_class_of_dev(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_CLASS_OF_DEV:
+               hci_cc_write_class_of_dev(hdev, skb);
+               break;
+
+       case HCI_OP_READ_VOICE_SETTING:
+               hci_cc_read_voice_setting(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_VOICE_SETTING:
+               hci_cc_write_voice_setting(hdev, skb);
+               break;
+
+       case HCI_OP_HOST_BUFFER_SIZE:
+               hci_cc_host_buffer_size(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_VERSION:
+               hci_cc_read_local_version(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_COMMANDS:
+               hci_cc_read_local_commands(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_FEATURES:
+               hci_cc_read_local_features(hdev, skb);
+               break;
+
+       case HCI_OP_READ_BUFFER_SIZE:
+               hci_cc_read_buffer_size(hdev, skb);
+               break;
+
+       case HCI_OP_READ_BD_ADDR:
+               hci_cc_read_bd_addr(hdev, skb);
+               break;
+
+       default:
+               BT_DBG("%s opcode 0x%x", hdev->name, opcode);
+               break;
+       }
+
+       if (ev->ncmd) {
+               atomic_set(&hdev->cmd_cnt, 1);
+               if (!skb_queue_empty(&hdev->cmd_q))
+                       hci_sched_cmd(hdev);
+       }
+}
+
+static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_cmd_status *ev = (void *) skb->data;
+       __u16 opcode;
+
+       skb_pull(skb, sizeof(*ev));
+
+       opcode = __le16_to_cpu(ev->opcode);
+
+       switch (opcode) {
+       case HCI_OP_INQUIRY:
+               hci_cs_inquiry(hdev, ev->status);
+               break;
+
+       case HCI_OP_CREATE_CONN:
+               hci_cs_create_conn(hdev, ev->status);
+               break;
+
+       case HCI_OP_ADD_SCO:
+               hci_cs_add_sco(hdev, ev->status);
+               break;
+
+       case HCI_OP_REMOTE_NAME_REQ:
+               hci_cs_remote_name_req(hdev, ev->status);
+               break;
+
+       case HCI_OP_SETUP_SYNC_CONN:
+               hci_cs_setup_sync_conn(hdev, ev->status);
+               break;
+
+       case HCI_OP_SNIFF_MODE:
+               hci_cs_sniff_mode(hdev, ev->status);
+               break;
+
+       case HCI_OP_EXIT_SNIFF_MODE:
+               hci_cs_exit_sniff_mode(hdev, ev->status);
+               break;
+
+       default:
+               BT_DBG("%s opcode 0x%x", hdev->name, opcode);
+               break;
+       }
+
+       if (ev->ncmd) {
+               atomic_set(&hdev->cmd_cnt, 1);
+               if (!skb_queue_empty(&hdev->cmd_q))
+                       hci_sched_cmd(hdev);
+       }
+}
+
+static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_role_change *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status %d", hdev->name, ev->status);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (conn) {
+               if (!ev->status) {
+                       if (ev->role)
+                               conn->link_mode &= ~HCI_LM_MASTER;
+                       else
+                               conn->link_mode |= HCI_LM_MASTER;
+               }
+
+               clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
+
+               hci_role_switch_cfm(conn, ev->status, ev->role);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
+       __le16 *ptr;
+       int i;
+
+       skb_pull(skb, sizeof(*ev));
+
+       BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
+
+       if (skb->len < ev->num_hndl * 4) {
+               BT_DBG("%s bad parameters", hdev->name);
+               return;
+       }
+
+       tasklet_disable(&hdev->tx_task);
+
+       for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
+               struct hci_conn *conn;
+               __u16  handle, count;
+
+               handle = __le16_to_cpu(get_unaligned(ptr++));
+               count  = __le16_to_cpu(get_unaligned(ptr++));
+
+               conn = hci_conn_hash_lookup_handle(hdev, handle);
+               if (conn) {
+                       conn->sent -= count;
+
+                       if (conn->type == ACL_LINK) {
+                               if ((hdev->acl_cnt += count) > hdev->acl_pkts)
+                                       hdev->acl_cnt = hdev->acl_pkts;
+                       } else {
+                               if ((hdev->sco_cnt += count) > hdev->sco_pkts)
+                                       hdev->sco_cnt = hdev->sco_pkts;
+                       }
+               }
+       }
+
+       hci_sched_tx(hdev);
+
+       tasklet_enable(&hdev->tx_task);
+}
+
+static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_mode_change *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1073,17 +1184,39 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-       if (conn && !ev->status) {
-               memcpy(conn->features, ev->features, sizeof(conn->features));
+       if (conn) {
+               conn->mode = ev->mode;
+               conn->interval = __le16_to_cpu(ev->interval);
+
+               if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+                       if (conn->mode == HCI_CM_ACTIVE)
+                               conn->power_save = 1;
+                       else
+                               conn->power_save = 0;
+               }
        }
 
        hci_dev_unlock(hdev);
 }
 
-/* Clock Offset */
+static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
 static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data;
+       struct hci_ev_clock_offset *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1103,10 +1236,9 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
        hci_dev_unlock(hdev);
 }
 
-/* Page Scan Repetition Mode */
 static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_pscan_rep_mode *ev = (struct hci_ev_pscan_rep_mode *) skb->data;
+       struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
        struct inquiry_entry *ie;
 
        BT_DBG("%s", hdev->name);
@@ -1121,10 +1253,91 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
        hci_dev_unlock(hdev);
 }
 
-/* Sniff Subrate */
+static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct inquiry_data data;
+       int num_rsp = *((__u8 *) skb->data);
+
+       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+
+       if (!num_rsp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
+               struct inquiry_info_with_rssi_and_pscan_mode *info = (void *) (skb->data + 1);
+
+               for (; num_rsp; num_rsp--) {
+                       bacpy(&data.bdaddr, &info->bdaddr);
+                       data.pscan_rep_mode     = info->pscan_rep_mode;
+                       data.pscan_period_mode  = info->pscan_period_mode;
+                       data.pscan_mode         = info->pscan_mode;
+                       memcpy(data.dev_class, info->dev_class, 3);
+                       data.clock_offset       = info->clock_offset;
+                       data.rssi               = info->rssi;
+                       info++;
+                       hci_inquiry_cache_update(hdev, &data);
+               }
+       } else {
+               struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
+
+               for (; num_rsp; num_rsp--) {
+                       bacpy(&data.bdaddr, &info->bdaddr);
+                       data.pscan_rep_mode     = info->pscan_rep_mode;
+                       data.pscan_period_mode  = info->pscan_period_mode;
+                       data.pscan_mode         = 0x00;
+                       memcpy(data.dev_class, info->dev_class, 3);
+                       data.clock_offset       = info->clock_offset;
+                       data.rssi               = info->rssi;
+                       info++;
+                       hci_inquiry_cache_update(hdev, &data);
+               }
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status %d", hdev->name, ev->status);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
+       if (!conn)
+               goto unlock;
+
+       if (!ev->status) {
+               conn->handle = __le16_to_cpu(ev->handle);
+               conn->state  = BT_CONNECTED;
+       } else
+               conn->state = BT_CLOSED;
+
+       hci_proto_connect_cfm(conn, ev->status);
+       if (ev->status)
+               hci_conn_del(conn);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
+static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
 static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_sniff_subrate *ev = (struct hci_ev_sniff_subrate *) skb->data;
+       struct hci_ev_sniff_subrate *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1138,22 +1351,42 @@ static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *s
        hci_dev_unlock(hdev);
 }
 
-void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data;
-       struct hci_ev_cmd_complete *ec;
-       struct hci_ev_cmd_status *cs;
-       u16 opcode, ocf, ogf;
+       struct inquiry_data data;
+       struct extended_inquiry_info *info = (void *) (skb->data + 1);
+       int num_rsp = *((__u8 *) skb->data);
 
-       skb_pull(skb, HCI_EVENT_HDR_SIZE);
+       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
-       BT_DBG("%s evt 0x%x", hdev->name, hdr->evt);
+       if (!num_rsp)
+               return;
 
-       switch (hdr->evt) {
-       case HCI_EV_NUM_COMP_PKTS:
-               hci_num_comp_pkts_evt(hdev, skb);
-               break;
+       hci_dev_lock(hdev);
+
+       for (; num_rsp; num_rsp--) {
+               bacpy(&data.bdaddr, &info->bdaddr);
+               data.pscan_rep_mode     = info->pscan_rep_mode;
+               data.pscan_period_mode  = info->pscan_period_mode;
+               data.pscan_mode         = 0x00;
+               memcpy(data.dev_class, info->dev_class, 3);
+               data.clock_offset       = info->clock_offset;
+               data.rssi               = info->rssi;
+               info++;
+               hci_inquiry_cache_update(hdev, &data);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_event_hdr *hdr = (void *) skb->data;
+       __u8 event = hdr->evt;
+
+       skb_pull(skb, HCI_EVENT_HDR_SIZE);
 
+       switch (event) {
        case HCI_EV_INQUIRY_COMPLETE:
                hci_inquiry_complete_evt(hdev, skb);
                break;
@@ -1162,44 +1395,64 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_inquiry_result_evt(hdev, skb);
                break;
 
-       case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
-               hci_inquiry_result_with_rssi_evt(hdev, skb);
-               break;
-
-       case HCI_EV_EXTENDED_INQUIRY_RESULT:
-               hci_extended_inquiry_result_evt(hdev, skb);
+       case HCI_EV_CONN_COMPLETE:
+               hci_conn_complete_evt(hdev, skb);
                break;
 
        case HCI_EV_CONN_REQUEST:
                hci_conn_request_evt(hdev, skb);
                break;
 
-       case HCI_EV_CONN_COMPLETE:
-               hci_conn_complete_evt(hdev, skb);
-               break;
-
        case HCI_EV_DISCONN_COMPLETE:
                hci_disconn_complete_evt(hdev, skb);
                break;
 
-       case HCI_EV_ROLE_CHANGE:
-               hci_role_change_evt(hdev, skb);
-               break;
-
-       case HCI_EV_MODE_CHANGE:
-               hci_mode_change_evt(hdev, skb);
-               break;
-
        case HCI_EV_AUTH_COMPLETE:
                hci_auth_complete_evt(hdev, skb);
                break;
 
+       case HCI_EV_REMOTE_NAME:
+               hci_remote_name_evt(hdev, skb);
+               break;
+
        case HCI_EV_ENCRYPT_CHANGE:
                hci_encrypt_change_evt(hdev, skb);
                break;
 
-       case HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE:
-               hci_change_conn_link_key_complete_evt(hdev, skb);
+       case HCI_EV_CHANGE_LINK_KEY_COMPLETE:
+               hci_change_link_key_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_REMOTE_FEATURES:
+               hci_remote_features_evt(hdev, skb);
+               break;
+
+       case HCI_EV_REMOTE_VERSION:
+               hci_remote_version_evt(hdev, skb);
+               break;
+
+       case HCI_EV_QOS_SETUP_COMPLETE:
+               hci_qos_setup_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_CMD_COMPLETE:
+               hci_cmd_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_CMD_STATUS:
+               hci_cmd_status_evt(hdev, skb);
+               break;
+
+       case HCI_EV_ROLE_CHANGE:
+               hci_role_change_evt(hdev, skb);
+               break;
+
+       case HCI_EV_NUM_COMP_PKTS:
+               hci_num_comp_pkts_evt(hdev, skb);
+               break;
+
+       case HCI_EV_MODE_CHANGE:
+               hci_mode_change_evt(hdev, skb);
                break;
 
        case HCI_EV_PIN_CODE_REQ:
@@ -1214,10 +1467,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_link_key_notify_evt(hdev, skb);
                break;
 
-       case HCI_EV_REMOTE_FEATURES:
-               hci_remote_features_evt(hdev, skb);
-               break;
-
        case HCI_EV_CLOCK_OFFSET:
                hci_clock_offset_evt(hdev, skb);
                break;
@@ -1226,82 +1475,32 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_pscan_rep_mode_evt(hdev, skb);
                break;
 
-       case HCI_EV_SNIFF_SUBRATE:
-               hci_sniff_subrate_evt(hdev, skb);
+       case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
+               hci_inquiry_result_with_rssi_evt(hdev, skb);
                break;
 
-       case HCI_EV_CMD_STATUS:
-               cs = (struct hci_ev_cmd_status *) skb->data;
-               skb_pull(skb, sizeof(cs));
-
-               opcode = __le16_to_cpu(cs->opcode);
-               ogf = hci_opcode_ogf(opcode);
-               ocf = hci_opcode_ocf(opcode);
-
-               switch (ogf) {
-               case OGF_INFO_PARAM:
-                       hci_cs_info_param(hdev, ocf, cs->status);
-                       break;
-
-               case OGF_HOST_CTL:
-                       hci_cs_host_ctl(hdev, ocf, cs->status);
-                       break;
-
-               case OGF_LINK_CTL:
-                       hci_cs_link_ctl(hdev, ocf, cs->status);
-                       break;
-
-               case OGF_LINK_POLICY:
-                       hci_cs_link_policy(hdev, ocf, cs->status);
-                       break;
-
-               default:
-                       BT_DBG("%s Command Status OGF %x", hdev->name, ogf);
-                       break;
-               }
-
-               if (cs->ncmd) {
-                       atomic_set(&hdev->cmd_cnt, 1);
-                       if (!skb_queue_empty(&hdev->cmd_q))
-                               hci_sched_cmd(hdev);
-               }
+       case HCI_EV_REMOTE_EXT_FEATURES:
+               hci_remote_ext_features_evt(hdev, skb);
                break;
 
-       case HCI_EV_CMD_COMPLETE:
-               ec = (struct hci_ev_cmd_complete *) skb->data;
-               skb_pull(skb, sizeof(*ec));
-
-               opcode = __le16_to_cpu(ec->opcode);
-               ogf = hci_opcode_ogf(opcode);
-               ocf = hci_opcode_ocf(opcode);
-
-               switch (ogf) {
-               case OGF_INFO_PARAM:
-                       hci_cc_info_param(hdev, ocf, skb);
-                       break;
-
-               case OGF_HOST_CTL:
-                       hci_cc_host_ctl(hdev, ocf, skb);
-                       break;
+       case HCI_EV_SYNC_CONN_COMPLETE:
+               hci_sync_conn_complete_evt(hdev, skb);
+               break;
 
-               case OGF_LINK_CTL:
-                       hci_cc_link_ctl(hdev, ocf, skb);
-                       break;
+       case HCI_EV_SYNC_CONN_CHANGED:
+               hci_sync_conn_changed_evt(hdev, skb);
+               break;
 
-               case OGF_LINK_POLICY:
-                       hci_cc_link_policy(hdev, ocf, skb);
-                       break;
+       case HCI_EV_SNIFF_SUBRATE:
+               hci_sniff_subrate_evt(hdev, skb);
+               break;
 
-               default:
-                       BT_DBG("%s Command Completed OGF %x", hdev->name, ogf);
-                       break;
-               }
+       case HCI_EV_EXTENDED_INQUIRY_RESULT:
+               hci_extended_inquiry_result_evt(hdev, skb);
+               break;
 
-               if (ec->ncmd) {
-                       atomic_set(&hdev->cmd_cnt, 1);
-                       if (!skb_queue_empty(&hdev->cmd_q))
-                               hci_sched_cmd(hdev);
-               }
+       default:
+               BT_DBG("%s event 0x%x", hdev->name, event);
                break;
        }
 
index 43dd637..8825102 100644 (file)
@@ -451,7 +451,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        goto drop;
                }
 
-               if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
+               if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
                        skb_queue_tail(&hdev->raw_q, skb);
                        hci_sched_tx(hdev);
                } else {
index 2583540..cef1e3e 100644 (file)
@@ -41,6 +41,26 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char
        return sprintf(buf, "%s\n", typetostr(hdev->type));
 }
 
+static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct hci_dev *hdev = dev_get_drvdata(dev);
+       char name[249];
+       int i;
+
+       for (i = 0; i < 248; i++)
+               name[i] = hdev->dev_name[i];
+
+       name[248] = '\0';
+       return sprintf(buf, "%s\n", name);
+}
+
+static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct hci_dev *hdev = dev_get_drvdata(dev);
+       return sprintf(buf, "0x%.2x%.2x%.2x\n",
+                       hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+}
+
 static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = dev_get_drvdata(dev);
@@ -49,6 +69,17 @@ static ssize_t show_address(struct device *dev, struct device_attribute *attr, c
        return sprintf(buf, "%s\n", batostr(&bdaddr));
 }
 
+static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct hci_dev *hdev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+                               hdev->features[0], hdev->features[1],
+                               hdev->features[2], hdev->features[3],
+                               hdev->features[4], hdev->features[5],
+                               hdev->features[6], hdev->features[7]);
+}
+
 static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = dev_get_drvdata(dev);
@@ -170,7 +201,10 @@ static ssize_t store_sniff_min_interval(struct device *dev, struct device_attrib
 }
 
 static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static DEVICE_ATTR(class, S_IRUGO, show_class, NULL);
 static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static DEVICE_ATTR(features, S_IRUGO, show_features, NULL);
 static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
 static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
 static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
@@ -185,7 +219,10 @@ static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
 
 static struct device_attribute *bt_attrs[] = {
        &dev_attr_type,
+       &dev_attr_name,
+       &dev_attr_class,
        &dev_attr_address,
+       &dev_attr_features,
        &dev_attr_manufacturer,
        &dev_attr_hci_version,
        &dev_attr_hci_revision,
index 66c7369..4bbacdd 100644 (file)
@@ -247,7 +247,7 @@ static inline int hidp_queue_report(struct hidp_session *session, unsigned char
 {
        struct sk_buff *skb;
 
-       BT_DBG("session %p hid %p data %p size %d", session, device, data, size);
+       BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
 
        if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
                BT_ERR("Can't allocate memory for new frame");
index 36ef27b..6fbbae7 100644 (file)
@@ -55,7 +55,9 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.8"
+#define VERSION "2.9"
+
+static u32 l2cap_feat_mask = 0x0000;
 
 static const struct proto_ops l2cap_sock_ops;
 
@@ -258,7 +260,119 @@ static void l2cap_chan_del(struct sock *sk, int err)
                sk->sk_state_change(sk);
 }
 
+static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
+{
+       u8 id;
+
+       /* Get next available identificator.
+        *    1 - 128 are used by kernel.
+        *  129 - 199 are reserved.
+        *  200 - 254 are used by utilities like l2ping, etc.
+        */
+
+       spin_lock_bh(&conn->lock);
+
+       if (++conn->tx_ident > 128)
+               conn->tx_ident = 1;
+
+       id = conn->tx_ident;
+
+       spin_unlock_bh(&conn->lock);
+
+       return id;
+}
+
+static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
+{
+       struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
+
+       BT_DBG("code 0x%2.2x", code);
+
+       if (!skb)
+               return -ENOMEM;
+
+       return hci_send_acl(conn->hcon, skb, 0);
+}
+
 /* ---- L2CAP connections ---- */
+static void l2cap_conn_start(struct l2cap_conn *conn)
+{
+       struct l2cap_chan_list *l = &conn->chan_list;
+       struct sock *sk;
+
+       BT_DBG("conn %p", conn);
+
+       read_lock(&l->lock);
+
+       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+               bh_lock_sock(sk);
+
+               if (sk->sk_type != SOCK_SEQPACKET) {
+                       l2cap_sock_clear_timer(sk);
+                       sk->sk_state = BT_CONNECTED;
+                       sk->sk_state_change(sk);
+               } else if (sk->sk_state == BT_CONNECT) {
+                       struct l2cap_conn_req req;
+                       l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+                       req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+                       req.psm  = l2cap_pi(sk)->psm;
+                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_REQ, sizeof(req), &req);
+               }
+
+               bh_unlock_sock(sk);
+       }
+
+       read_unlock(&l->lock);
+}
+
+static void l2cap_conn_ready(struct l2cap_conn *conn)
+{
+       BT_DBG("conn %p", conn);
+
+       if (conn->chan_list.head || !hlist_empty(&l2cap_sk_list.head)) {
+               struct l2cap_info_req req;
+
+               req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+
+               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
+               conn->info_ident = l2cap_get_ident(conn);
+
+               mod_timer(&conn->info_timer,
+                       jiffies + msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+
+               l2cap_send_cmd(conn, conn->info_ident,
+                                       L2CAP_INFO_REQ, sizeof(req), &req);
+       }
+}
+
+/* Notify sockets that we cannot guaranty reliability anymore */
+static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
+{
+       struct l2cap_chan_list *l = &conn->chan_list;
+       struct sock *sk;
+
+       BT_DBG("conn %p", conn);
+
+       read_lock(&l->lock);
+
+       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+               if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
+                       sk->sk_err = err;
+       }
+
+       read_unlock(&l->lock);
+}
+
+static void l2cap_info_timeout(unsigned long arg)
+{
+       struct l2cap_conn *conn = (void *) arg;
+
+       conn->info_ident = 0;
+
+       l2cap_conn_start(conn);
+}
+
 static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
@@ -279,6 +393,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
        conn->src = &hcon->hdev->bdaddr;
        conn->dst = &hcon->dst;
 
+       conn->feat_mask = 0;
+
+       init_timer(&conn->info_timer);
+       conn->info_timer.function = l2cap_info_timeout;
+       conn->info_timer.data = (unsigned long) conn;
+
        spin_lock_init(&conn->lock);
        rwlock_init(&conn->chan_list.lock);
 
@@ -318,40 +438,6 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, stru
        write_unlock_bh(&l->lock);
 }
 
-static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
-{
-       u8 id;
-
-       /* Get next available identificator.
-        *    1 - 128 are used by kernel.
-        *  129 - 199 are reserved.
-        *  200 - 254 are used by utilities like l2ping, etc.
-        */
-
-       spin_lock_bh(&conn->lock);
-
-       if (++conn->tx_ident > 128)
-               conn->tx_ident = 1;
-
-       id = conn->tx_ident;
-
-       spin_unlock_bh(&conn->lock);
-
-       return id;
-}
-
-static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
-{
-       struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
-
-       BT_DBG("code 0x%2.2x", code);
-
-       if (!skb)
-               return -ENOMEM;
-
-       return hci_send_acl(conn->hcon, skb, 0);
-}
-
 /* ---- Socket interface ---- */
 static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
 {
@@ -508,7 +594,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 
        /* Default config options */
        pi->conf_len = 0;
-       pi->conf_mtu = L2CAP_DEFAULT_MTU;
        pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 }
 
@@ -530,7 +615,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
        INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
        sk->sk_destruct = l2cap_sock_destruct;
-       sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
+       sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
 
        sock_reset_flag(sk, SOCK_ZAPPED);
 
@@ -650,6 +735,11 @@ static int l2cap_do_connect(struct sock *sk)
        l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
        if (hcon->state == BT_CONNECTED) {
+               if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) {
+                       l2cap_conn_ready(conn);
+                       goto done;
+               }
+
                if (sk->sk_type == SOCK_SEQPACKET) {
                        struct l2cap_conn_req req;
                        l2cap_pi(sk)->ident = l2cap_get_ident(conn);
@@ -958,7 +1048,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                opts.imtu     = l2cap_pi(sk)->imtu;
                opts.omtu     = l2cap_pi(sk)->omtu;
                opts.flush_to = l2cap_pi(sk)->flush_to;
-               opts.mode     = 0x00;
+               opts.mode     = L2CAP_MODE_BASIC;
 
                len = min_t(unsigned int, sizeof(opts), optlen);
                if (copy_from_user((char *) &opts, optval, len)) {
@@ -1007,7 +1097,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                opts.imtu     = l2cap_pi(sk)->imtu;
                opts.omtu     = l2cap_pi(sk)->omtu;
                opts.flush_to = l2cap_pi(sk)->flush_to;
-               opts.mode     = 0x00;
+               opts.mode     = L2CAP_MODE_BASIC;
 
                len = min_t(unsigned int, len, sizeof(opts));
                if (copy_to_user(optval, (char *) &opts, len))
@@ -1084,52 +1174,6 @@ static int l2cap_sock_release(struct socket *sock)
        return err;
 }
 
-static void l2cap_conn_ready(struct l2cap_conn *conn)
-{
-       struct l2cap_chan_list *l = &conn->chan_list;
-       struct sock *sk;
-
-       BT_DBG("conn %p", conn);
-
-       read_lock(&l->lock);
-
-       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-               bh_lock_sock(sk);
-
-               if (sk->sk_type != SOCK_SEQPACKET) {
-                       l2cap_sock_clear_timer(sk);
-                       sk->sk_state = BT_CONNECTED;
-                       sk->sk_state_change(sk);
-               } else if (sk->sk_state == BT_CONNECT) {
-                       struct l2cap_conn_req req;
-                       l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-                       req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-                       req.psm  = l2cap_pi(sk)->psm;
-                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_REQ, sizeof(req), &req);
-               }
-
-               bh_unlock_sock(sk);
-       }
-
-       read_unlock(&l->lock);
-}
-
-/* Notify sockets that we cannot guaranty reliability anymore */
-static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
-{
-       struct l2cap_chan_list *l = &conn->chan_list;
-       struct sock *sk;
-
-       BT_DBG("conn %p", conn);
-
-       read_lock(&l->lock);
-       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-               if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
-                       sk->sk_err = err;
-       }
-       read_unlock(&l->lock);
-}
-
 static void l2cap_chan_ready(struct sock *sk)
 {
        struct sock *parent = bt_sk(sk)->parent;
@@ -1256,11 +1300,11 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned
                break;
 
        case 2:
-               *val = __le16_to_cpu(*((__le16 *)opt->val));
+               *val = __le16_to_cpu(*((__le16 *) opt->val));
                break;
 
        case 4:
-               *val = __le32_to_cpu(*((__le32 *)opt->val));
+               *val = __le32_to_cpu(*((__le32 *) opt->val));
                break;
 
        default:
@@ -1332,6 +1376,8 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
        int len = pi->conf_len;
        int type, hint, olen;
        unsigned long val;
+       struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
+       u16 mtu = L2CAP_DEFAULT_MTU;
        u16 result = L2CAP_CONF_SUCCESS;
 
        BT_DBG("sk %p", sk);
@@ -1344,7 +1390,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
 
                switch (type) {
                case L2CAP_CONF_MTU:
-                       pi->conf_mtu = val;
+                       mtu = val;
                        break;
 
                case L2CAP_CONF_FLUSH_TO:
@@ -1354,6 +1400,11 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
                case L2CAP_CONF_QOS:
                        break;
 
+               case L2CAP_CONF_RFC:
+                       if (olen == sizeof(rfc))
+                               memcpy(&rfc, (void *) val, olen);
+                       break;
+
                default:
                        if (hint)
                                break;
@@ -1368,12 +1419,24 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
                /* Configure output options and let the other side know
                 * which ones we don't like. */
 
-               if (pi->conf_mtu < pi->omtu)
+               if (rfc.mode == L2CAP_MODE_BASIC) {
+                       if (mtu < pi->omtu)
+                               result = L2CAP_CONF_UNACCEPT;
+                       else {
+                               pi->omtu = mtu;
+                               pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
+                       }
+
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+               } else {
                        result = L2CAP_CONF_UNACCEPT;
-               else
-                       pi->omtu = pi->conf_mtu;
 
-               l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+                       memset(&rfc, 0, sizeof(rfc));
+                       rfc.mode = L2CAP_MODE_BASIC;
+
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
+                                               sizeof(rfc), (unsigned long) &rfc);
+               }
        }
 
        rsp->scid   = cpu_to_le16(pi->dcid);
@@ -1397,6 +1460,23 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla
        return ptr - data;
 }
 
+static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+{
+       struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
+
+       if (rej->reason != 0x0000)
+               return 0;
+
+       if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
+                                       cmd->ident == conn->info_ident) {
+               conn->info_ident = 0;
+               del_timer(&conn->info_timer);
+               l2cap_conn_start(conn);
+       }
+
+       return 0;
+}
+
 static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_chan_list *list = &conn->chan_list;
@@ -1577,16 +1657,19 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
 
-       /* Output config done. */
-       l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
-
        /* Reset config buffer. */
        l2cap_pi(sk)->conf_len = 0;
 
+       if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE))
+               goto unlock;
+
        if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
                sk->sk_state = BT_CONNECTED;
                l2cap_chan_ready(sk);
-       } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
+               goto unlock;
+       }
+
+       if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
                u8 req[64];
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
                                        l2cap_build_conf_req(sk, req), req);
@@ -1646,7 +1729,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (flags & 0x01)
                goto done;
 
-       /* Input config done */
        l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
 
        if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
@@ -1711,16 +1793,27 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_info_req *req = (struct l2cap_info_req *) data;
-       struct l2cap_info_rsp rsp;
        u16 type;
 
        type = __le16_to_cpu(req->type);
 
        BT_DBG("type 0x%4.4x", type);
 
-       rsp.type   = cpu_to_le16(type);
-       rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
-       l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
+       if (type == L2CAP_IT_FEAT_MASK) {
+               u8 buf[8];
+               struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
+               rsp->type   = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+               rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
+               put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
+               l2cap_send_cmd(conn, cmd->ident,
+                                       L2CAP_INFO_RSP, sizeof(buf), buf);
+       } else {
+               struct l2cap_info_rsp rsp;
+               rsp.type   = cpu_to_le16(type);
+               rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
+               l2cap_send_cmd(conn, cmd->ident,
+                                       L2CAP_INFO_RSP, sizeof(rsp), &rsp);
+       }
 
        return 0;
 }
@@ -1735,6 +1828,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
        BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
 
+       conn->info_ident = 0;
+
+       del_timer(&conn->info_timer);
+
+       if (type == L2CAP_IT_FEAT_MASK)
+               conn->feat_mask = __le32_to_cpu(get_unaligned((__le32 *) rsp->data));
+
+       l2cap_conn_start(conn);
+
        return 0;
 }
 
@@ -1764,7 +1866,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
 
                switch (cmd.code) {
                case L2CAP_COMMAND_REJ:
-                       /* FIXME: We should process this */
+                       l2cap_command_rej(conn, &cmd, data);
                        break;
 
                case L2CAP_CONN_REQ:
index bb72207..e7ac6ba 100644 (file)
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/init.h>
-#include <linux/freezer.h>
 #include <linux/wait.h>
 #include <linux/device.h>
 #include <linux/net.h>
 #include <linux/mutex.h>
+#include <linux/kthread.h>
 
 #include <net/sock.h>
 #include <asm/uaccess.h>
@@ -68,7 +68,6 @@ static DEFINE_MUTEX(rfcomm_mutex);
 static unsigned long rfcomm_event;
 
 static LIST_HEAD(session_list);
-static atomic_t terminate, running;
 
 static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
@@ -1850,26 +1849,6 @@ static inline void rfcomm_process_sessions(void)
        rfcomm_unlock();
 }
 
-static void rfcomm_worker(void)
-{
-       BT_DBG("");
-
-       while (!atomic_read(&terminate)) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
-                       /* No pending events. Let's sleep.
-                        * Incoming connections and data will wake us up. */
-                       schedule();
-               }
-               set_current_state(TASK_RUNNING);
-
-               /* Process stuff */
-               clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
-               rfcomm_process_sessions();
-       }
-       return;
-}
-
 static int rfcomm_add_listener(bdaddr_t *ba)
 {
        struct sockaddr_l2 addr;
@@ -1935,22 +1914,28 @@ static void rfcomm_kill_listener(void)
 
 static int rfcomm_run(void *unused)
 {
-       rfcomm_thread = current;
-
-       atomic_inc(&running);
+       BT_DBG("");
 
-       daemonize("krfcommd");
        set_user_nice(current, -10);
 
-       BT_DBG("");
-
        rfcomm_add_listener(BDADDR_ANY);
 
-       rfcomm_worker();
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
+                       /* No pending events. Let's sleep.
+                        * Incoming connections and data will wake us up. */
+                       schedule();
+               }
+               set_current_state(TASK_RUNNING);
+
+               /* Process stuff */
+               clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
+               rfcomm_process_sessions();
+       }
 
        rfcomm_kill_listener();
 
-       atomic_dec(&running);
        return 0;
 }
 
@@ -2059,7 +2044,11 @@ static int __init rfcomm_init(void)
 
        hci_register_cb(&rfcomm_cb);
 
-       kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
+       rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd");
+       if (IS_ERR(rfcomm_thread)) {
+               hci_unregister_cb(&rfcomm_cb);
+               return PTR_ERR(rfcomm_thread);
+       }
 
        if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0)
                BT_ERR("Failed to create RFCOMM info file");
@@ -2081,14 +2070,7 @@ static void __exit rfcomm_exit(void)
 
        hci_unregister_cb(&rfcomm_cb);
 
-       /* Terminate working thread.
-        * ie. Set terminate flag and wake it up */
-       atomic_inc(&terminate);
-       rfcomm_schedule(RFCOMM_SCHED_STATE);
-
-       /* Wait until thread is running */
-       while (atomic_read(&running))
-               schedule();
+       kthread_stop(rfcomm_thread);
 
 #ifdef CONFIG_BT_RFCOMM_TTY
        rfcomm_cleanup_ttys();
index 22a8320..e447651 100644 (file)
@@ -189,6 +189,23 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
        return conn ? &conn->dev : NULL;
 }
 
+static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
+{
+       struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
+       bdaddr_t bdaddr;
+       baswap(&bdaddr, &dev->dst);
+       return sprintf(buf, "%s\n", batostr(&bdaddr));
+}
+
+static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
+{
+       struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
+       return sprintf(buf, "%d\n", dev->channel);
+}
+
+static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
+
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 {
        struct rfcomm_dev *dev;
@@ -281,6 +298,14 @@ out:
                return err;
        }
 
+       dev_set_drvdata(dev->tty_dev, dev);
+
+       if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
+               BT_ERR("Failed to create address attribute");
+
+       if (device_create_file(dev->tty_dev, &dev_attr_channel) < 0)
+               BT_ERR("Failed to create channel attribute");
+
        return dev->id;
 }
 
index 65b6fb1..82d0dfd 100644 (file)
@@ -189,7 +189,7 @@ static int sco_connect(struct sock *sk)
        struct sco_conn *conn;
        struct hci_conn *hcon;
        struct hci_dev  *hdev;
-       int err = 0;
+       int err, type;
 
        BT_DBG("%s -> %s", batostr(src), batostr(dst));
 
@@ -200,7 +200,9 @@ static int sco_connect(struct sock *sk)
 
        err = -ENOMEM;
 
-       hcon = hci_connect(hdev, SCO_LINK, dst);
+       type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK;
+
+       hcon = hci_connect(hdev, type, dst);
        if (!hcon)
                goto done;
 
@@ -224,6 +226,7 @@ static int sco_connect(struct sock *sk)
                sk->sk_state = BT_CONNECT;
                sco_sock_set_timer(sk, sk->sk_sndtimeo);
        }
+
 done:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
@@ -846,7 +849,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
 {
        BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
 
-       if (hcon->type != SCO_LINK)
+       if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
                return 0;
 
        if (!status) {
@@ -865,10 +868,11 @@ static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
-       if (hcon->type != SCO_LINK)
+       if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
                return 0;
 
        sco_conn_del(hcon, bt_err(reason));
+
        return 0;
 }
 
index 38b03da..8726589 100644 (file)
@@ -1553,7 +1553,7 @@ gso:
                        return rc;
                }
                if (unlikely((netif_queue_stopped(dev) ||
-                            netif_subqueue_stopped(dev, skb->queue_mapping)) &&
+                            netif_subqueue_stopped(dev, skb)) &&
                             skb->next))
                        return NETDEV_TX_BUSY;
        } while (skb->next);
@@ -1661,7 +1661,7 @@ gso:
                q = dev->qdisc;
                if (q->enqueue) {
                        /* reset queue_mapping to zero */
-                       skb->queue_mapping = 0;
+                       skb_set_queue_mapping(skb, 0);
                        rc = q->enqueue(skb, q);
                        qdisc_run(dev);
                        spin_unlock(&dev->queue_lock);
@@ -1692,7 +1692,7 @@ gso:
                        HARD_TX_LOCK(dev, cpu);
 
                        if (!netif_queue_stopped(dev) &&
-                           !netif_subqueue_stopped(dev, skb->queue_mapping)) {
+                           !netif_subqueue_stopped(dev, skb)) {
                                rc = 0;
                                if (!dev_hard_start_xmit(skb, dev)) {
                                        HARD_TX_UNLOCK(dev);
index 67ba991..05979e3 100644 (file)
@@ -1438,6 +1438,9 @@ int neigh_table_clear(struct neigh_table *tbl)
        free_percpu(tbl->stats);
        tbl->stats = NULL;
 
+       kmem_cache_destroy(tbl->kmem_cachep);
+       tbl->kmem_cachep = NULL;
+
        return 0;
 }
 
index 95daba6..bf8d18f 100644 (file)
@@ -67,7 +67,7 @@ static void queue_process(struct work_struct *work)
                local_irq_save(flags);
                netif_tx_lock(dev);
                if ((netif_queue_stopped(dev) ||
-                    netif_subqueue_stopped(dev, skb->queue_mapping)) ||
+                    netif_subqueue_stopped(dev, skb)) ||
                     dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
                        skb_queue_head(&npinfo->txq, skb);
                        netif_tx_unlock(dev);
@@ -269,7 +269,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
                     tries > 0; --tries) {
                        if (netif_tx_trylock(dev)) {
                                if (!netif_queue_stopped(dev) &&
-                                   !netif_subqueue_stopped(dev, skb->queue_mapping))
+                                   !netif_subqueue_stopped(dev, skb))
                                        status = dev->hard_start_xmit(skb, dev);
                                netif_tx_unlock(dev);
 
index c4719ed..de33f36 100644 (file)
@@ -2603,8 +2603,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        skb->network_header = skb->tail;
        skb->transport_header = skb->network_header + sizeof(struct iphdr);
        skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
-       skb->queue_mapping = pkt_dev->cur_queue_map;
-
+       skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
        iph = ip_hdr(skb);
        udph = udp_hdr(skb);
 
@@ -2941,8 +2940,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        skb->network_header = skb->tail;
        skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
        skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
-       skb->queue_mapping = pkt_dev->cur_queue_map;
-
+       skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
        iph = ipv6_hdr(skb);
        udph = udp_hdr(skb);
 
@@ -3385,7 +3383,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
        if ((netif_queue_stopped(odev) ||
             (pkt_dev->skb &&
-             netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping))) ||
+             netif_subqueue_stopped(odev, pkt_dev->skb))) ||
            need_resched()) {
                idle_start = getCurUs();
 
@@ -3402,7 +3400,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
                pkt_dev->idle_acc += getCurUs() - idle_start;
 
                if (netif_queue_stopped(odev) ||
-                   netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
+                   netif_subqueue_stopped(odev, pkt_dev->skb)) {
                        pkt_dev->next_tx_us = getCurUs();       /* TODO */
                        pkt_dev->next_tx_ns = 0;
                        goto out;       /* Try the next interface */
@@ -3431,7 +3429,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
        netif_tx_lock_bh(odev);
        if (!netif_queue_stopped(odev) &&
-           !netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
+           !netif_subqueue_stopped(odev, pkt_dev->skb)) {
 
                atomic_inc(&(pkt_dev->skb->users));
              retry_now:
index 70d9b5d..4e2c84f 100644 (file)
@@ -2045,7 +2045,7 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
        if (copy > 0) {
                if (copy > len)
                        copy = len;
-               sg[elt].page = virt_to_page(skb->data + offset);
+               sg_set_page(&sg[elt], virt_to_page(skb->data + offset));
                sg[elt].offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
                sg[elt].length = copy;
                elt++;
@@ -2065,7 +2065,7 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
 
                        if (copy > len)
                                copy = len;
-                       sg[elt].page = frag->page;
+                       sg_set_page(&sg[elt], frag->page);
                        sg[elt].offset = frag->page_offset+offset-start;
                        sg[elt].length = copy;
                        elt++;
index 0f37455..d8a3509 100644 (file)
@@ -68,3 +68,4 @@ module_exit(dccp_diag_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCP inet_diag handler");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, DCCPDIAG_GETSOCK);
index 44f6e17..222549a 100644 (file)
@@ -1037,8 +1037,8 @@ module_exit(dccp_v4_exit);
  * values directly, Also cover the case where the protocol is not specified,
  * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
  */
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 33, 6);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 0, 6);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");
index cac5354..bbadd66 100644 (file)
@@ -1219,8 +1219,8 @@ module_exit(dccp_v6_exit);
  * values directly, Also cover the case where the protocol is not specified,
  * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
  */
-MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-33-type-6");
-MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-0-type-6");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");
index 72e6ab6..8117776 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/scatterlist.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/mm.h>
@@ -390,9 +391,7 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        icv[3] = crc >> 24;
 
        crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
-       sg.page = virt_to_page(pos);
-       sg.offset = offset_in_page(pos);
-       sg.length = len + 4;
+       sg_init_one(&sg, pos, len + 4);
        return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
 }
 
@@ -485,9 +484,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        plen = skb->len - hdr_len - 12;
 
        crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
-       sg.page = virt_to_page(pos);
-       sg.offset = offset_in_page(pos);
-       sg.length = plen + 4;
+       sg_init_one(&sg, pos, plen + 4);
        if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG ": TKIP: failed to decrypt "
@@ -539,11 +536,12 @@ static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
                printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
                return -1;
        }
-       sg[0].page = virt_to_page(hdr);
+       sg_init_table(sg, 2);
+       sg_set_page(&sg[0], virt_to_page(hdr));
        sg[0].offset = offset_in_page(hdr);
        sg[0].length = 16;
 
-       sg[1].page = virt_to_page(data);
+       sg_set_page(&sg[1], virt_to_page(data));
        sg[1].offset = offset_in_page(data);
        sg[1].length = data_len;
 
index 8d18245..9693429 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/scatterlist.h>
 #include <linux/skbuff.h>
 #include <linux/mm.h>
 #include <asm/string.h>
@@ -170,9 +171,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        icv[3] = crc >> 24;
 
        crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
-       sg.page = virt_to_page(pos);
-       sg.offset = offset_in_page(pos);
-       sg.length = len + 4;
+       sg_init_one(&sg, pos, len + 4);
        return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
 }
 
@@ -212,9 +211,7 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        plen = skb->len - hdr_len - 8;
 
        crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
-       sg.page = virt_to_page(pos);
-       sg.offset = offset_in_page(pos);
-       sg.length = plen + 4;
+       sg_init_one(&sg, pos, plen + 4);
        if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
                return -7;
 
index 7eb83eb..dc429b6 100644 (file)
@@ -815,6 +815,12 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
            nlmsg_len(nlh) < hdrlen)
                return -EINVAL;
 
+#ifdef CONFIG_KMOD
+       if (inet_diag_table[nlh->nlmsg_type] == NULL)
+               request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
+                              NETLINK_INET_DIAG, nlh->nlmsg_type);
+#endif
+
        if (inet_diag_table[nlh->nlmsg_type] == NULL)
                return -ENOENT;
 
@@ -914,3 +920,4 @@ static void __exit inet_diag_exit(void)
 module_init(inet_diag_init);
 module_exit(inet_diag_exit);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_INET_DIAG);
index 3904d21..2fbcc7d 100644 (file)
@@ -56,3 +56,4 @@ static void __exit tcp_diag_exit(void)
 module_init(tcp_diag_init);
 module_exit(tcp_diag_exit);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, TCPDIAG_GETSOCK);
index 67cd066..66a9139 100644 (file)
@@ -483,6 +483,7 @@ static int ah6_init_state(struct xfrm_state *x)
                break;
        case XFRM_MODE_TUNNEL:
                x->props.header_len += sizeof(struct ipv6hdr);
+               break;
        default:
                goto error;
        }
index b071543..72a6598 100644 (file)
@@ -360,6 +360,7 @@ static int esp6_init_state(struct xfrm_state *x)
                break;
        case XFRM_MODE_TUNNEL:
                x->props.header_len += sizeof(struct ipv6hdr);
+               break;
        default:
                goto error;
        }
index 6675261..a84a233 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/crypto.h>
 #include <linux/err.h>
 #include <linux/mm.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
@@ -138,9 +138,7 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
        *icv = cpu_to_le32(~crc32_le(~0, data, data_len));
 
        crypto_blkcipher_setkey(tfm, rc4key, klen);
-       sg.page = virt_to_page(data);
-       sg.offset = offset_in_page(data);
-       sg.length = data_len + WEP_ICV_LEN;
+       sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
        crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
 }
 
@@ -204,9 +202,7 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
        __le32 crc;
 
        crypto_blkcipher_setkey(tfm, rc4key, klen);
-       sg.page = virt_to_page(data);
-       sg.offset = offset_in_page(data);
-       sg.length = data_len + WEP_ICV_LEN;
+       sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
        crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
 
        crc = cpu_to_le32(~crc32_le(~0, data, data_len));
index be57cf3..421281d 100644 (file)
@@ -266,7 +266,7 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
        int busy;
        int nores;
        int len = skb->len;
-       int subq = skb->queue_mapping;
+       int subq = skb_get_queue_mapping(skb);
        struct sk_buff *skb_res = NULL;
 
        start = master->slaves;
@@ -284,7 +284,7 @@ restart:
                if (slave->qdisc_sleeping != q)
                        continue;
                if (netif_queue_stopped(slave) ||
-                   netif_subqueue_stopped(slave, subq) ||
+                   __netif_subqueue_stopped(slave, subq) ||
                    !netif_running(slave)) {
                        busy = 1;
                        continue;
@@ -294,7 +294,7 @@ restart:
                case 0:
                        if (netif_tx_trylock(slave)) {
                                if (!netif_queue_stopped(slave) &&
-                                   !netif_subqueue_stopped(slave, subq) &&
+                                   !__netif_subqueue_stopped(slave, subq) &&
                                    slave->hard_start_xmit(skb, slave) == 0) {
                                        netif_tx_unlock(slave);
                                        master->slaves = NEXT_SLAVE(q);
index 7818107..cbd64b2 100644 (file)
@@ -726,7 +726,8 @@ void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
 
        /* set up scatter list */
        end = skb_tail_pointer(skb);
-       sg.page = virt_to_page(auth);
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, virt_to_page(auth));
        sg.offset = (unsigned long)(auth) % PAGE_SIZE;
        sg.length = end - (unsigned char *)auth;
 
index f983a36..658476c 100644 (file)
@@ -56,7 +56,7 @@
 #include <linux/ipv6.h>
 #include <linux/net.h>
 #include <linux/inet.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 #include <linux/crypto.h>
 #include <net/sock.h>
 
@@ -1513,7 +1513,8 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
                struct hash_desc desc;
 
                /* Sign the message.  */
-               sg.page = virt_to_page(&cookie->c);
+               sg_init_table(&sg, 1);
+               sg_set_page(&sg, virt_to_page(&cookie->c));
                sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE;
                sg.length = bodysize;
                keylen = SCTP_SECRET_SIZE;
@@ -1585,7 +1586,8 @@ struct sctp_association *sctp_unpack_cookie(
 
        /* Check the signature.  */
        keylen = SCTP_SECRET_SIZE;
-       sg.page = virt_to_page(bear_cookie);
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, virt_to_page(bear_cookie));
        sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE;
        sg.length = bodysize;
        key = (char *)ep->secret_key[ep->current_key];
index bfb6a29..32be431 100644 (file)
@@ -197,9 +197,9 @@ encryptor(struct scatterlist *sg, void *data)
                int i = (page_pos + outbuf->page_base) >> PAGE_CACHE_SHIFT;
                in_page = desc->pages[i];
        } else {
-               in_page = sg->page;
+               in_page = sg_page(sg);
        }
-       desc->infrags[desc->fragno].page = in_page;
+       sg_set_page(&desc->infrags[desc->fragno], in_page);
        desc->fragno++;
        desc->fraglen += sg->length;
        desc->pos += sg->length;
@@ -215,11 +215,11 @@ encryptor(struct scatterlist *sg, void *data)
        if (ret)
                return ret;
        if (fraglen) {
-               desc->outfrags[0].page = sg->page;
+               sg_set_page(&desc->outfrags[0], sg_page(sg));
                desc->outfrags[0].offset = sg->offset + sg->length - fraglen;
                desc->outfrags[0].length = fraglen;
                desc->infrags[0] = desc->outfrags[0];
-               desc->infrags[0].page = in_page;
+               sg_set_page(&desc->infrags[0], in_page);
                desc->fragno = 1;
                desc->fraglen = fraglen;
        } else {
@@ -287,7 +287,7 @@ decryptor(struct scatterlist *sg, void *data)
        if (ret)
                return ret;
        if (fraglen) {
-               desc->frags[0].page = sg->page;
+               sg_set_page(&desc->frags[0], sg_page(sg));
                desc->frags[0].offset = sg->offset + sg->length - fraglen;
                desc->frags[0].length = fraglen;
                desc->fragno = 1;
index 6a59180..3d1f7cd 100644 (file)
@@ -1059,7 +1059,7 @@ xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len,
                do {
                        if (thislen > page_len)
                                thislen = page_len;
-                       sg->page = buf->pages[i];
+                       sg_set_page(sg, buf->pages[i]);
                        sg->offset = page_offset;
                        sg->length = thislen;
                        ret = actor(sg, data);
index 5ced62c..313d4be 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/pfkeyv2.h>
 #include <linux/crypto.h>
+#include <linux/scatterlist.h>
 #include <net/xfrm.h>
 #if defined(CONFIG_INET_AH) || defined(CONFIG_INET_AH_MODULE) || defined(CONFIG_INET6_AH) || defined(CONFIG_INET6_AH_MODULE)
 #include <net/ah.h>
@@ -552,7 +553,7 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
                if (copy > len)
                        copy = len;
 
-               sg.page = virt_to_page(skb->data + offset);
+               sg_set_page(&sg, virt_to_page(skb->data + offset));
                sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
                sg.length = copy;
 
@@ -577,7 +578,7 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
                        if (copy > len)
                                copy = len;
 
-                       sg.page = frag->page;
+                       sg_set_page(&sg, frag->page);
                        sg.offset = frag->page_offset + offset-start;
                        sg.length = copy;
 
index 28e480c..d716b76 100755 (executable)
@@ -13,6 +13,7 @@
 #      Random bits by Matt Mackall <mpm@selenic.com>
 #      M68k port by Geert Uytterhoeven and Andreas Schwab
 #      AVR32 port by Haavard Skinnemoen <hskinnemoen@atmel.com>
+#      PARISC port by Kyle McMartin <kyle@parisc-linux.org>
 #
 #      Usage:
 #      objdump -d vmlinux | scripts/checkstack.pl [arch]
@@ -61,6 +62,8 @@ my (@stack, $re, $x, $xs);
        } elsif ($arch eq 'mips') {
                #88003254:       27bdffe0        addiu   sp,sp,-32
                $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+       } elsif ($arch eq 'parisc' || $arch eq 'parisc64') {
+               $re = qr/.*ldo ($x{1,8})\(sp\),sp/o;
        } elsif ($arch eq 'ppc') {
                #c00029f4:       94 21 ff 30     stwu    r1,-208(r1)
                $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o;
index e4eeb59..b9bb32d 100644 (file)
@@ -1274,8 +1274,12 @@ ConfigMainWindow::ConfigMainWindow(void)
        QMenuBar* menu;
        bool ok;
        int x, y, width, height;
+       char title[256];
 
        QWidget *d = configApp->desktop();
+       snprintf(title, sizeof(title), _("Linux Kernel v%s Configuration"),
+               getenv("KERNELVERSION"));
+       setCaption(title);
 
        width = configSettings->readNumEntry("/window width", d->width() - 64);
        height = configSettings->readNumEntry("/window height", d->height() - 64);
index 91c15da..d802b5a 100644 (file)
@@ -525,6 +525,20 @@ static int do_ssb_entry(const char *filename,
        return 1;
 }
 
+/* Looks like: virtio:dNvN */
+static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
+                          char *alias)
+{
+       id->device = TO_NATIVE(id->device);
+       id->vendor = TO_NATIVE(id->vendor);
+
+       strcpy(alias, "virtio:");
+       ADD(alias, "d", 1, id->device);
+       ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor);
+
+       return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -651,6 +665,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct ssb_device_id), "ssb",
                         do_ssb_entry, mod);
+       else if (sym_is(symname, "__mod_virtio_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct virtio_device_id), "virtio",
+                        do_virtio_entry, mod);
        free(zeros);
 }
 
index 43f9027..bf67871 100644 (file)
@@ -190,7 +190,8 @@ int cap_inode_killpriv(struct dentry *dentry)
        return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
 }
 
-static inline int cap_from_disk(__le32 *caps, struct linux_binprm *bprm,
+static inline int cap_from_disk(struct vfs_cap_data *caps,
+                               struct linux_binprm *bprm,
                                int size)
 {
        __u32 magic_etc;
@@ -198,7 +199,7 @@ static inline int cap_from_disk(__le32 *caps, struct linux_binprm *bprm,
        if (size != XATTR_CAPS_SZ)
                return -EINVAL;
 
-       magic_etc = le32_to_cpu(caps[0]);
+       magic_etc = le32_to_cpu(caps->magic_etc);
 
        switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
        case VFS_CAP_REVISION:
@@ -206,8 +207,8 @@ static inline int cap_from_disk(__le32 *caps, struct linux_binprm *bprm,
                        bprm->cap_effective = true;
                else
                        bprm->cap_effective = false;
-               bprm->cap_permitted = to_cap_t( le32_to_cpu(caps[1]) );
-               bprm->cap_inheritable = to_cap_t( le32_to_cpu(caps[2]) );
+               bprm->cap_permitted = to_cap_t(le32_to_cpu(caps->permitted));
+               bprm->cap_inheritable = to_cap_t(le32_to_cpu(caps->inheritable));
                return 0;
        default:
                return -EINVAL;
@@ -219,7 +220,7 @@ static int get_file_caps(struct linux_binprm *bprm)
 {
        struct dentry *dentry;
        int rc = 0;
-       __le32 v1caps[XATTR_CAPS_SZ];
+       struct vfs_cap_data incaps;
        struct inode *inode;
 
        if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) {
@@ -232,8 +233,14 @@ static int get_file_caps(struct linux_binprm *bprm)
        if (!inode->i_op || !inode->i_op->getxattr)
                goto out;
 
-       rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &v1caps,
-                                                       XATTR_CAPS_SZ);
+       rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, NULL, 0);
+       if (rc > 0) {
+               if (rc == XATTR_CAPS_SZ)
+                       rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS,
+                                               &incaps, XATTR_CAPS_SZ);
+               else
+                       rc = -EINVAL;
+       }
        if (rc == -ENODATA || rc == -EOPNOTSUPP) {
                /* no data, that's ok */
                rc = 0;
@@ -242,7 +249,7 @@ static int get_file_caps(struct linux_binprm *bprm)
        if (rc < 0)
                goto out;
 
-       rc = cap_from_disk(v1caps, bprm, rc);
+       rc = cap_from_disk(&incaps, bprm, rc);
        if (rc)
                printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
                        __FUNCTION__, rc, bprm->filename);
index 24e1b18..9f3124b 100644 (file)
@@ -2977,11 +2977,7 @@ static int selinux_task_prctl(int option,
 
 static int selinux_task_wait(struct task_struct *p)
 {
-       u32 perm;
-
-       perm = signal_to_av(p->exit_signal);
-
-       return task_has_perm(p, current, perm);
+       return task_has_perm(p, current, PROCESS__SIGCHLD);
 }
 
 static void selinux_task_reparent_to_init(struct task_struct *p)
index 4c3aa8e..df0774c 100644 (file)
@@ -93,15 +93,16 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
 
 static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
 {
+       unsigned long flags;
        struct snd_kctl_event *cread;
        
-       spin_lock(&ctl->read_lock);
+       spin_lock_irqsave(&ctl->read_lock, flags);
        while (!list_empty(&ctl->events)) {
                cread = snd_kctl_event(ctl->events.next);
                list_del(&cread->list);
                kfree(cread);
        }
-       spin_unlock(&ctl->read_lock);
+       spin_unlock_irqrestore(&ctl->read_lock, flags);
 }
 
 static int snd_ctl_release(struct inode *inode, struct file *file)
index fe31bb5..37c47fb 100644 (file)
@@ -189,7 +189,6 @@ void snd_tea575x_init(struct snd_tea575x *tea)
        tea->vd.owner = tea->card->module;
        strcpy(tea->vd.name, tea->tea5759 ? "TEA5759 radio" : "TEA5757 radio");
        tea->vd.type = VID_TYPE_TUNER;
-       tea->vd.hardware = VID_HARDWARE_RTRACK; /* FIXME: assign new number */
        tea->vd.release = snd_tea575x_release;
        video_set_drvdata(&tea->vd, tea);
        tea->vd.fops = &tea->fops;
index 91f9e6a..2dba752 100644 (file)
@@ -165,7 +165,7 @@ struct snd_bt87x_board {
        unsigned no_digital:1;  /* No digital input */
 };
 
-static const __devinitdata struct snd_bt87x_board snd_bt87x_boards[] = {
+static __devinitdata struct snd_bt87x_board snd_bt87x_boards[] = {
        [SND_BT87X_BOARD_UNKNOWN] = {
                .dig_rate = 32000, /* just a guess */
        },
@@ -848,7 +848,7 @@ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
        int i;
        const struct pci_device_id *supported;
 
-       supported = pci_match_device(&driver, pci);
+       supported = pci_match_id(snd_bt87x_ids, pci);
        if (supported && supported->driver_data > 0)
                return supported->driver_data;
 
index 187533e..ad4cb38 100644 (file)
@@ -626,24 +626,19 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
                snd_hda_get_codec_name(codec, bus->card->mixername,
                                       sizeof(bus->card->mixername));
 
-#ifdef CONFIG_SND_HDA_GENERIC
        if (is_generic_config(codec)) {
                err = snd_hda_parse_generic_codec(codec);
                goto patched;
        }
-#endif
        if (codec->preset && codec->preset->patch) {
                err = codec->preset->patch(codec);
                goto patched;
        }
 
        /* call the default parser */
-#ifdef CONFIG_SND_HDA_GENERIC
        err = snd_hda_parse_generic_codec(codec);
-#else
-       printk(KERN_ERR "hda-codec: No codec parser is available\n");
-       err = -ENODEV;
-#endif
+       if (err < 0)
+               printk(KERN_ERR "hda-codec: No codec parser is available\n");
 
  patched:
        if (err < 0) {
index a79d0ed..20c5e62 100644 (file)
@@ -245,7 +245,14 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
 /*
  * generic codec parser
  */
+#ifdef CONFIG_SND_HDA_GENERIC
 int snd_hda_parse_generic_codec(struct hda_codec *codec);
+#else
+static inline int snd_hda_parse_generic_codec(struct hda_codec *codec)
+{
+       return -ENODEV;
+}
+#endif
 
 /*
  * generic proc interface
@@ -303,16 +310,17 @@ enum {
 
 extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
 
+#define AUTO_CFG_MAX_OUTS      5
+
 struct auto_pin_cfg {
        int line_outs;
-       hda_nid_t line_out_pins[5]; /* sorted in the order of
-                                    * Front/Surr/CLFE/Side
-                                    */
+       /* sorted in the order of Front/Surr/CLFE/Side */
+       hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
        int speaker_outs;
-       hda_nid_t speaker_pins[5];
+       hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
        int hp_outs;
        int line_out_type;      /* AUTO_PIN_XXX_OUT */
-       hda_nid_t hp_pins[5];
+       hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
        hda_nid_t input_pins[AUTO_PIN_LAST];
        hda_nid_t dig_out_pin;
        hda_nid_t dig_in_pin;
index 54cfd45..0ee8ae4 100644 (file)
@@ -72,7 +72,7 @@ struct ad198x_spec {
        unsigned int num_kctl_alloc, num_kctl_used;
        struct snd_kcontrol_new *kctl_alloc;
        struct hda_input_mux private_imux;
-       hda_nid_t private_dac_nids[4];
+       hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
        unsigned int jack_present :1;
 
@@ -612,7 +612,8 @@ static void ad1986a_hp_automute(struct hda_codec *codec)
        unsigned int present;
 
        present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = (present & 0x80000000) != 0;
+       /* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
+       spec->jack_present = !(present & 0x80000000);
        ad1986a_update_hp(codec);
 }
 
index 2468f31..6c54793 100644 (file)
@@ -50,7 +50,7 @@ struct cmi_spec {
 
        /* playback */
        struct hda_multi_out multiout;
-       hda_nid_t dac_nids[4];          /* NID for each DAC */
+       hda_nid_t dac_nids[AUTO_CFG_MAX_OUTS];  /* NID for each DAC */
        int num_dacs;
 
        /* capture */
@@ -73,7 +73,6 @@ struct cmi_spec {
        unsigned int pin_def_confs;
 
        /* multichannel pins */
-       hda_nid_t multich_pin[4];       /* max 8-channel */
        struct hda_verb multi_init[9];  /* 2 verbs for each pin + terminator */
 };
 
index 080e300..6aa0739 100644 (file)
@@ -85,7 +85,7 @@ struct conexant_spec {
        unsigned int num_kctl_alloc, num_kctl_used;
        struct snd_kcontrol_new *kctl_alloc;
        struct hda_input_mux private_imux;
-       hda_nid_t private_dac_nids[4];
+       hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
 };
 
@@ -554,10 +554,16 @@ static struct snd_kcontrol_new cxt5045_mixers[] = {
                .get = conexant_mux_enum_get,
                .put = conexant_mux_enum_put
        },
-       HDA_CODEC_VOLUME("Int Mic Volume", 0x1a, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Switch", 0x1a, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Ext Mic Volume", 0x1a, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Ext Mic Switch", 0x1a, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
        HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -576,16 +582,15 @@ static struct hda_verb cxt5045_init_verbs[] = {
        {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
        /* HP, Amp  */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-       {0x17, AC_VERB_SET_CONNECT_SEL,0x01},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE,
-        AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x01},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE,
-        AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x02},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE,
-        AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE,
-        AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x04},
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x10, AC_VERB_SET_CONNECT_SEL, 0x1},
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x11, AC_VERB_SET_CONNECT_SEL, 0x1},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
        /* Record selector: Int mic */
        {0x1a, AC_VERB_SET_CONNECT_SEL,0x1},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
index 53b0428..d9f78c8 100644 (file)
@@ -238,7 +238,7 @@ struct alc_spec {
        unsigned int num_kctl_alloc, num_kctl_used;
        struct snd_kcontrol_new *kctl_alloc;
        struct hda_input_mux private_imux;
-       hda_nid_t private_dac_nids[5];
+       hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
        /* hooks */
        void (*init_hook)(struct hda_codec *codec);
index bf95019..f9b2c43 100644 (file)
@@ -111,6 +111,7 @@ struct sigmatel_spec {
        unsigned int alt_switch: 1;
        unsigned int hp_detect: 1;
        unsigned int gpio_mute: 1;
+       unsigned int no_vol_knob :1;
 
        unsigned int gpio_mask, gpio_data;
 
@@ -1930,7 +1931,8 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
        }
        if (spec->multiout.hp_nid) {
                const char *pfx;
-               if (old_num_dacs == spec->multiout.num_dacs)
+               if (old_num_dacs == spec->multiout.num_dacs &&
+                   spec->no_vol_knob)
                        pfx = "Master";
                else
                        pfx = "Headphone";
@@ -2487,6 +2489,7 @@ static int patch_stac9200(struct hda_codec *codec)
        codec->spec = spec;
        spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
        spec->pin_nids = stac9200_pin_nids;
+       spec->no_vol_knob = 1;
        spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
                                                        stac9200_models,
                                                        stac9200_cfg_tbl);
@@ -2541,6 +2544,7 @@ static int patch_stac925x(struct hda_codec *codec)
        codec->spec = spec;
        spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
        spec->pin_nids = stac925x_pin_nids;
+       spec->no_vol_knob = 1;
        spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
                                                        stac925x_models,
                                                        stac925x_cfg_tbl);
index 33b5e1f..4cdf3e6 100644 (file)
@@ -114,7 +114,7 @@ struct via_spec {
        unsigned int num_kctl_alloc, num_kctl_used;
        struct snd_kcontrol_new *kctl_alloc;
        struct hda_input_mux private_imux;
-       hda_nid_t private_dac_nids[4];  
+       hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
index 131ec48..88dc840 100644 (file)
@@ -106,11 +106,14 @@ static void spu_write_wait(void)
 static void spu_memset(u32 toi, u32 what, int length)
 {
        int i;
+       unsigned long flags;
        snd_assert(length % 4 == 0, return);
        for (i = 0; i < length; i++) {
                if (!(i % 8))
                        spu_write_wait();
+               local_irq_save(flags);
                writel(what, toi + SPU_MEMORY_BASE);
+               local_irq_restore(flags);
                toi++;
        }
 }
@@ -118,6 +121,7 @@ static void spu_memset(u32 toi, u32 what, int length)
 /* spu_memload - write to SPU address space */
 static void spu_memload(u32 toi, void *from, int length)
 {
+       unsigned long flags;
        u32 *froml = from;
        u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
        int i;
@@ -128,7 +132,9 @@ static void spu_memload(u32 toi, void *from, int length)
                if (!(i % 8))
                        spu_write_wait();
                val = *froml;
+               local_irq_save(flags);
                writel(val, to);
+               local_irq_restore(flags);
                froml++;
                to++;
        }
@@ -138,28 +144,36 @@ static void spu_memload(u32 toi, void *from, int length)
 static void spu_disable(void)
 {
        int i;
+       unsigned long flags;
        u32 regval;
        spu_write_wait();
        regval = readl(ARM_RESET_REGISTER);
        regval |= 1;
        spu_write_wait();
+       local_irq_save(flags);
        writel(regval, ARM_RESET_REGISTER);
+       local_irq_restore(flags);
        for (i = 0; i < 64; i++) {
                spu_write_wait();
                regval = readl(SPU_REGISTER_BASE + (i * 0x80));
                regval = (regval & ~0x4000) | 0x8000;
                spu_write_wait();
+               local_irq_save(flags);
                writel(regval, SPU_REGISTER_BASE + (i * 0x80));
+               local_irq_restore(flags);
        }
 }
 
 /* spu_enable - set spu registers to enable sound output */
 static void spu_enable(void)
 {
+       unsigned long flags;
        u32 regval = readl(ARM_RESET_REGISTER);
        regval &= ~1;
        spu_write_wait();
+       local_irq_save(flags);
        writel(regval, ARM_RESET_REGISTER);
+       local_irq_restore(flags);
 }
 
 /* 
@@ -168,25 +182,34 @@ static void spu_enable(void)
 */
 static void spu_reset(void)
 {
+       unsigned long flags;
        spu_disable();
        spu_memset(0, 0, 0x200000 / 4);
        /* Put ARM7 in endless loop */
+       local_irq_save(flags);
        ctrl_outl(0xea000002, SPU_MEMORY_BASE);
+       local_irq_restore(flags);
        spu_enable();
 }
 
 /* aica_chn_start - write to spu to start playback */
 static void aica_chn_start(void)
 {
+       unsigned long flags;
        spu_write_wait();
+       local_irq_save(flags);
        writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
+       local_irq_restore(flags);
 }
 
 /* aica_chn_halt - write to spu to halt playback */
 static void aica_chn_halt(void)
 {
+       unsigned long flags;
        spu_write_wait();
+       local_irq_save(flags);
        writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
+       local_irq_restore(flags);
 }
 
 /* ALSA code below */
@@ -213,12 +236,13 @@ static int aica_dma_transfer(int channels, int buffer_size,
        int q, err, period_offset;
        struct snd_card_aica *dreamcastcard;
        struct snd_pcm_runtime *runtime;
-       err = 0;
+       unsigned long flags;
        dreamcastcard = substream->pcm->private_data;
        period_offset = dreamcastcard->clicks;
        period_offset %= (AICA_PERIOD_NUMBER / channels);
        runtime = substream->runtime;
        for (q = 0; q < channels; q++) {
+               local_irq_save(flags);
                err = dma_xfer(AICA_DMA_CHANNEL,
                               (unsigned long) (runtime->dma_area +
                                                (AICA_BUFFER_SIZE * q) /
@@ -228,9 +252,12 @@ static int aica_dma_transfer(int channels, int buffer_size,
                               AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
                               AICA_PERIOD_SIZE * period_offset,
                               buffer_size / channels, AICA_DMA_MODE);
-               if (unlikely(err < 0))
+               if (unlikely(err < 0)) {
+                       local_irq_restore(flags);
                        break;
+               }
                dma_wait_for_completion(AICA_DMA_CHANNEL);
+               local_irq_restore(flags);
        }
        return err;
 }
index 9785382..f8c7a12 100644 (file)
@@ -400,65 +400,44 @@ static void snd_cs4231_mce_up(struct snd_cs4231 *chip)
 
 static void snd_cs4231_mce_down(struct snd_cs4231 *chip)
 {
-       unsigned long flags;
-       unsigned long end_time;
-       int timeout;
+       unsigned long flags, timeout;
+       int reg;
 
-       spin_lock_irqsave(&chip->lock, flags);
        snd_cs4231_busy_wait(chip);
+       spin_lock_irqsave(&chip->lock, flags);
 #ifdef CONFIG_SND_DEBUG
        if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT)
                snd_printdd("mce_down [%p] - auto calibration time out (0)\n",
                            CS4231U(chip, REGSEL));
 #endif
        chip->mce_bit &= ~CS4231_MCE;
-       timeout = __cs4231_readb(chip, CS4231U(chip, REGSEL));
-       __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f),
+       reg = __cs4231_readb(chip, CS4231U(chip, REGSEL));
+       __cs4231_writeb(chip, chip->mce_bit | (reg & 0x1f),
                        CS4231U(chip, REGSEL));
-       if (timeout == 0x80)
-               snd_printdd("mce_down [%p]: serious init problem - "
-                           "codec still busy\n",
-                           chip->port);
-       if ((timeout & CS4231_MCE) == 0) {
+       if (reg == 0x80)
+               snd_printdd("mce_down [%p]: serious init problem "
+                           "- codec still busy\n", chip->port);
+       if ((reg & CS4231_MCE) == 0) {
                spin_unlock_irqrestore(&chip->lock, flags);
                return;
        }
 
        /*
-        * Wait for (possible -- during init auto-calibration may not be set)
-        * calibration process to start. Needs upto 5 sample periods on AD1848
-        * which at the slowest possible rate of 5.5125 kHz means 907 us.
+        * Wait for auto-calibration (AC) process to finish, i.e. ACI to go low.
         */
-       msleep(1);
-
-       /* check condition up to 250ms */
-       end_time = jiffies + msecs_to_jiffies(250);
-       while (snd_cs4231_in(chip, CS4231_TEST_INIT) &
-               CS4231_CALIB_IN_PROGRESS) {
-
+       timeout = jiffies + msecs_to_jiffies(250);
+       do {
                spin_unlock_irqrestore(&chip->lock, flags);
-               if (time_after(jiffies, end_time)) {
-                       snd_printk("mce_down - "
-                                  "auto calibration time out (2)\n");
-                       return;
-               }
-               msleep(1);
-               spin_lock_irqsave(&chip->lock, flags);
-       }
-
-       /* check condition up to 100ms */
-       end_time = jiffies + msecs_to_jiffies(100);
-       while (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) {
-               spin_unlock_irqrestore(&chip->lock, flags);
-               if (time_after(jiffies, end_time)) {
-                       snd_printk("mce_down - "
-                                  "auto calibration time out (3)\n");
-                       return;
-               }
                msleep(1);
                spin_lock_irqsave(&chip->lock, flags);
-       }
+               reg = snd_cs4231_in(chip, CS4231_TEST_INIT);
+               reg &= CS4231_CALIB_IN_PROGRESS;
+       } while (reg && time_before(jiffies, timeout));
        spin_unlock_irqrestore(&chip->lock, flags);
+
+       if (reg)
+               snd_printk(KERN_ERR
+                          "mce_down - auto calibration time out (2)\n");
 }
 
 static void snd_cs4231_advance_dma(struct cs4231_dma_control *dma_cont,
index 743568f..59410f4 100644 (file)
        .bInterfaceClass = USB_CLASS_AUDIO,
        .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
 },
+{
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .idVendor = 0x046d,
+       .idProduct = 0x08f5,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+},
 {
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
                       USB_DEVICE_ID_MATCH_INT_CLASS |