summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/hwmon/w83l785ts3
-rw-r--r--Documentation/kdump/kdump.txt5
-rw-r--r--Documentation/lguest/lguest.c62
-rw-r--r--Documentation/powerpc/mpc52xx-device-tree-bindings.txt11
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas22
-rw-r--r--MAINTAINERS18
-rw-r--r--Makefile6
-rw-r--r--arch/alpha/kernel/osf_sys.c69
-rw-r--r--arch/frv/mm/Makefile2
-rw-r--r--arch/ia64/ia32/ia32_signal.c2
-rw-r--r--arch/ia64/kernel/acpi.c2
-rw-r--r--arch/ia64/kernel/irq.c4
-rw-r--r--arch/ia64/kernel/palinfo.c2
-rw-r--r--arch/ia64/kernel/perfmon.c199
-rw-r--r--arch/ia64/kernel/signal.c15
-rw-r--r--arch/ia64/kernel/smp.c68
-rw-r--r--arch/ia64/kernel/time.c5
-rw-r--r--arch/ia64/kernel/topology.c16
-rw-r--r--arch/ia64/kvm/kvm-ia64.c3
-rw-r--r--arch/m32r/Makefile2
-rw-r--r--arch/m32r/defconfig863
-rw-r--r--arch/m32r/kernel/vmlinux.lds.S3
-rw-r--r--arch/m68knommu/kernel/asm-offsets.c1
-rw-r--r--arch/m68knommu/kernel/entry.S9
-rw-r--r--arch/m68knommu/kernel/setup.c2
-rw-r--r--arch/m68knommu/kernel/signal.c21
-rw-r--r--arch/m68knommu/kernel/traps.c88
-rw-r--r--arch/m68knommu/kernel/vmlinux.lds.S3
-rw-r--r--arch/m68knommu/platform/5206e/config.c2
-rw-r--r--arch/m68knommu/platform/5272/config.c4
-rw-r--r--arch/m68knommu/platform/528x/config.c266
-rw-r--r--arch/m68knommu/platform/5307/config.c3
-rw-r--r--arch/m68knommu/platform/coldfire/entry.S18
-rw-r--r--arch/mips/kernel/binfmt_elfn32.c5
-rw-r--r--arch/mips/kernel/binfmt_elfo32.c5
-rw-r--r--arch/mips/kernel/irixioctl.c55
-rw-r--r--arch/mips/kernel/kspd.c1
-rw-r--r--arch/powerpc/boot/dts/mpc8610_hpcd.dts23
-rw-r--r--arch/powerpc/configs/ps3_defconfig132
-rw-r--r--arch/powerpc/kernel/smp.c2
-rw-r--r--arch/powerpc/kernel/time.c4
-rw-r--r--arch/powerpc/mm/slb.c27
-rw-r--r--arch/powerpc/platforms/cell/spufs/coredump.c1
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c6
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c9
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c4
-rw-r--r--arch/powerpc/sysdev/xilinx_intc.c2
-rw-r--r--arch/sparc/kernel/setup.c5
-rw-r--r--arch/sparc/mm/fault.c61
-rw-r--r--arch/sparc/prom/init.c7
-rw-r--r--arch/sparc/prom/memory.c235
-rw-r--r--arch/sparc64/kernel/pci.c130
-rw-r--r--arch/sparc64/kernel/pci_common.c6
-rw-r--r--arch/sparc64/kernel/pci_impl.h9
-rw-r--r--arch/sparc64/kernel/process.c6
-rw-r--r--arch/sparc64/kernel/signal.c6
-rw-r--r--arch/sparc64/kernel/signal32.c6
-rw-r--r--arch/x86/kvm/i8254.c6
-rw-r--r--arch/x86/kvm/lapic.c6
-rw-r--r--block/blk-barrier.c3
-rw-r--r--block/blk-core.c5
-rw-r--r--block/blk-settings.c20
-rw-r--r--block/blk-tag.c8
-rw-r--r--block/bsg.c14
-rw-r--r--block/elevator.c5
-rw-r--r--block/scsi_ioctl.c5
-rw-r--r--crypto/authenc.c5
-rw-r--r--crypto/cryptd.c4
-rw-r--r--crypto/eseqiv.c3
-rw-r--r--drivers/base/cpu.c10
-rw-r--r--drivers/block/cciss.c8
-rw-r--r--drivers/block/ub.c63
-rw-r--r--drivers/block/virtio_blk.c44
-rw-r--r--drivers/char/i8k.c6
-rw-r--r--drivers/char/mmtimer.c24
-rw-r--r--drivers/char/synclink.c16
-rw-r--r--drivers/char/tty_audit.c1
-rw-r--r--drivers/char/tty_io.c1
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c6
-rw-r--r--drivers/firewire/fw-sbp2.c4
-rw-r--r--drivers/gpio/pca953x.c4
-rw-r--r--drivers/hwmon/adt7473.c45
-rw-r--r--drivers/hwmon/asb100.c4
-rw-r--r--drivers/hwmon/lm75.c5
-rw-r--r--drivers/hwmon/smsc47b397.c17
-rw-r--r--drivers/hwmon/w83793.c26
-rw-r--r--drivers/hwmon/w83l785ts.c4
-rw-r--r--drivers/ide/ide-probe.c3
-rw-r--r--drivers/ieee1394/nodemgr.c5
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c3
-rw-r--r--drivers/lguest/lguest_device.c68
-rw-r--r--drivers/lguest/lguest_user.c4
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c14
-rw-r--r--drivers/mtd/devices/mtdram.c11
-rw-r--r--drivers/mtd/devices/phram.c13
-rw-r--r--drivers/mtd/devices/pmc551.c27
-rw-r--r--drivers/mtd/devices/slram.c15
-rw-r--r--drivers/mtd/maps/uclinux.c6
-rw-r--r--drivers/mtd/mtdpart.c8
-rw-r--r--drivers/mtd/nand/at91_nand.c42
-rw-r--r--drivers/net/fec.c125
-rw-r--r--drivers/net/fec.h4
-rw-r--r--drivers/net/fec_mpc52xx.c97
-rw-r--r--drivers/net/fec_mpc52xx.h19
-rw-r--r--drivers/net/virtio_net.c96
-rw-r--r--drivers/pcmcia/au1000_db1x00.c6
-rw-r--r--drivers/pcmcia/au1000_generic.c11
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c14
-rw-r--r--drivers/pcmcia/au1000_xxs1500.c2
-rw-r--r--drivers/pcmcia/cardbus.c2
-rw-r--r--drivers/pcmcia/ds.c2
-rw-r--r--drivers/pcmcia/i82092.c6
-rw-r--r--drivers/pcmcia/omap_cf.c2
-rw-r--r--drivers/pcmcia/pd6729.c6
-rw-r--r--drivers/pcmcia/pxa2xx_lubbock.c8
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c4
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c2
-rw-r--r--drivers/pcmcia/sa1100_assabet.c4
-rw-r--r--drivers/pcmcia/sa1100_badge4.c8
-rw-r--r--drivers/pcmcia/sa1100_cerf.c2
-rw-r--r--drivers/pcmcia/sa1100_jornada720.c4
-rw-r--r--drivers/pcmcia/sa1100_neponset.c4
-rw-r--r--drivers/pcmcia/sa1100_shannon.c8
-rw-r--r--drivers/pcmcia/sa1100_simpad.c2
-rw-r--r--drivers/pcmcia/soc_common.c17
-rw-r--r--drivers/pcmcia/soc_common.h1
-rw-r--r--drivers/pnp/pnpbios/rsparser.c6
-rw-r--r--drivers/ps3/ps3-lpm.c1
-rw-r--r--drivers/ps3/ps3-sys-manager.c7
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c2
-rw-r--r--drivers/scsi/53c700.c6
-rw-r--r--drivers/scsi/Kconfig3
-rw-r--r--drivers/scsi/a100u2w.c2
-rw-r--r--drivers/scsi/aacraid/aachba.c133
-rw-r--r--drivers/scsi/aacraid/aacraid.h28
-rw-r--r--drivers/scsi/aacraid/comminit.c2
-rw-r--r--drivers/scsi/aacraid/commsup.c34
-rw-r--r--drivers/scsi/aacraid/linit.c22
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c6
-rw-r--r--drivers/scsi/constants.c10
-rw-r--r--drivers/scsi/dpt/dpti_ioctl.h16
-rw-r--r--drivers/scsi/dpt/dptsig.h8
-rw-r--r--drivers/scsi/dpt/sys_info.h4
-rw-r--r--drivers/scsi/dpt_i2o.c640
-rw-r--r--drivers/scsi/dpti.h15
-rw-r--r--drivers/scsi/gdth.c2
-rw-r--r--drivers/scsi/hptiop.c6
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c7
-rw-r--r--drivers/scsi/ibmvscsi/viosrp.h9
-rw-r--r--drivers/scsi/initio.c2
-rw-r--r--drivers/scsi/ipr.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c17
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.h1
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c13
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h6
-rw-r--r--drivers/scsi/mvsas.c4
-rw-r--r--drivers/scsi/ncr53c8xx.c2
-rw-r--r--drivers/scsi/qla1280.c4
-rw-r--r--drivers/scsi/scsi.c23
-rw-r--r--drivers/scsi/scsi_error.c15
-rw-r--r--drivers/scsi/scsi_lib.c7
-rw-r--r--drivers/scsi/scsi_tgt_lib.c2
-rw-r--r--drivers/scsi/u14-34f.c6
-rw-r--r--drivers/serial/8250.c3
-rw-r--r--drivers/serial/8250_early.c2
-rw-r--r--drivers/serial/8250_pci.c14
-rw-r--r--drivers/serial/jsm/jsm.h1
-rw-r--r--drivers/serial/jsm/jsm_driver.c6
-rw-r--r--drivers/serial/mpc52xx_uart.c2
-rw-r--r--drivers/serial/sunhv.c2
-rw-r--r--drivers/serial/sunsab.c2
-rw-r--r--drivers/serial/sunsu.c2
-rw-r--r--drivers/serial/sunzilog.c2
-rw-r--r--drivers/spi/spi_bfin5xx.c7
-rw-r--r--drivers/spi/spi_s3c24xx.c6
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/atm/Kconfig4
-rw-r--r--drivers/usb/c67x00/Makefile9
-rw-r--r--drivers/usb/c67x00/c67x00-drv.c243
-rw-r--r--drivers/usb/c67x00/c67x00-hcd.c412
-rw-r--r--drivers/usb/c67x00/c67x00-hcd.h133
-rw-r--r--drivers/usb/c67x00/c67x00-ll-hpi.c480
-rw-r--r--drivers/usb/c67x00/c67x00-sched.c1170
-rw-r--r--drivers/usb/c67x00/c67x00.h294
-rw-r--r--drivers/usb/core/message.c4
-rw-r--r--drivers/usb/gadget/Kconfig20
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/ether.c8
-rw-r--r--drivers/usb/gadget/file_storage.c25
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c2404
-rw-r--r--drivers/usb/gadget/pxa27x_udc.h487
-rw-r--r--drivers/usb/gadget/serial.c90
-rw-r--r--drivers/usb/gadget/zero.c370
-rw-r--r--drivers/usb/host/Kconfig39
-rw-r--r--drivers/usb/host/Makefile4
-rw-r--r--drivers/usb/host/isp1760-hcd.c2231
-rw-r--r--drivers/usb/host/isp1760-hcd.h206
-rw-r--r--drivers/usb/host/isp1760-if.c298
-rw-r--r--drivers/usb/host/ohci-hub.c2
-rw-r--r--drivers/usb/host/uhci-hcd.c74
-rw-r--r--drivers/usb/host/uhci-hcd.h5
-rw-r--r--drivers/usb/misc/ldusb.c28
-rw-r--r--drivers/usb/misc/usbtest.c276
-rw-r--r--drivers/usb/serial/aircable.c98
-rw-r--r--drivers/usb/serial/airprime.c63
-rw-r--r--drivers/usb/serial/ark3116.c54
-rw-r--r--drivers/usb/serial/ch341.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.c8
-rw-r--r--drivers/usb/serial/ftdi_sio.h11
-rw-r--r--drivers/usb/serial/mos7840.c5
-rw-r--r--drivers/usb/storage/Kconfig3
-rw-r--r--drivers/usb/storage/cypress_atacb.c2
-rw-r--r--drivers/usb/storage/isd200.c2
-rw-r--r--drivers/usb/storage/libusual.c2
-rw-r--r--drivers/usb/storage/onetouch.c4
-rw-r--r--drivers/usb/storage/unusual_devs.h28
-rw-r--r--drivers/usb/storage/usb.c3
-rw-r--r--drivers/virtio/virtio.c38
-rw-r--r--drivers/virtio/virtio_balloon.c12
-rw-r--r--drivers/virtio/virtio_pci.c34
-rw-r--r--drivers/virtio/virtio_ring.c5
-rw-r--r--fs/anon_inodes.c13
-rw-r--r--fs/autofs4/expire.c26
-rw-r--r--fs/autofs4/root.c38
-rw-r--r--fs/autofs4/waitq.c2
-rw-r--r--fs/compat.c1
-rw-r--r--fs/dnotify.c2
-rw-r--r--fs/eventfd.c15
-rw-r--r--fs/eventpoll.c23
-rw-r--r--fs/exec.c1
-rw-r--r--fs/fcntl.c1
-rw-r--r--fs/file.c23
-rw-r--r--fs/file_table.c1
-rw-r--r--fs/fuse/file.c2
-rw-r--r--fs/jffs2/build.c31
-rw-r--r--fs/jffs2/dir.c42
-rw-r--r--fs/jffs2/erase.c9
-rw-r--r--fs/jffs2/fs.c14
-rw-r--r--fs/jffs2/gc.c8
-rw-r--r--fs/jffs2/nodelist.h5
-rw-r--r--fs/jffs2/nodemgmt.c2
-rw-r--r--fs/jffs2/os-linux.h2
-rw-r--r--fs/jffs2/readinode.c16
-rw-r--r--fs/jffs2/scan.c9
-rw-r--r--fs/jffs2/super.c15
-rw-r--r--fs/jffs2/wbuf.c2
-rw-r--r--fs/jffs2/write.c17
-rw-r--r--fs/jffs2/xattr.c4
-rw-r--r--fs/locks.c1
-rw-r--r--fs/ocfs2/cluster/sys.c2
-rw-r--r--fs/ocfs2/dlm/dlmdebug.c8
-rw-r--r--fs/ocfs2/file.c4
-rw-r--r--fs/ocfs2/localalloc.c4
-rw-r--r--fs/ocfs2/stack_o2cb.c2
-rw-r--r--fs/ocfs2/stack_user.c2
-rw-r--r--fs/ocfs2/symlink.c2
-rw-r--r--fs/open.c1
-rw-r--r--fs/proc/array.c1
-rw-r--r--fs/proc/base.c1
-rw-r--r--fs/select.c3
-rw-r--r--fs/signalfd.c17
-rw-r--r--fs/timerfd.c11
-rw-r--r--fs/utimes.c17
-rw-r--r--include/asm-arm/div64.h2
-rw-r--r--include/asm-frv/unaligned.h6
-rw-r--r--include/asm-generic/div64.h7
-rw-r--r--include/asm-ia64/cpu.h2
-rw-r--r--include/asm-ia64/dmi.h5
-rw-r--r--include/asm-ia64/io.h5
-rw-r--r--include/asm-ia64/thread_info.h13
-rw-r--r--include/asm-m68k/div64.h1
-rw-r--r--include/asm-m68knommu/dma.h3
-rw-r--r--include/asm-m68knommu/param.h7
-rw-r--r--include/asm-mips/div64.h6
-rw-r--r--include/asm-mn10300/div64.h3
-rw-r--r--include/asm-powerpc/ps3.h3
-rw-r--r--include/asm-sparc/oplib.h17
-rw-r--r--include/asm-sparc/page.h5
-rw-r--r--include/asm-um/div64.h1
-rw-r--r--include/asm-x86/div64.h34
-rw-r--r--include/asm-x86/dmi.h1
-rw-r--r--include/asm-x86/io_32.h5
-rw-r--r--include/crypto/scatterwalk.h4
-rw-r--r--include/linux/Kbuild5
-rw-r--r--include/linux/anon_inodes.h3
-rw-r--r--include/linux/calc64.h49
-rw-r--r--include/linux/clocksource.h2
-rw-r--r--include/linux/compat.h3
-rw-r--r--include/linux/device.h8
-rw-r--r--include/linux/fdtable.h99
-rw-r--r--include/linux/file.h86
-rw-r--r--include/linux/init_task.h2
-rw-r--r--include/linux/irq.h1
-rw-r--r--include/linux/jiffies.h2
-rw-r--r--include/linux/math64.h84
-rw-r--r--include/linux/module.h19
-rw-r--r--include/linux/mtd/jedec.h66
-rw-r--r--include/linux/mtd/mtd.h6
-rw-r--r--include/linux/mtd/pmc551.h5
-rw-r--r--include/linux/pci_ids.h1
-rw-r--r--include/linux/poll.h2
-rw-r--r--include/linux/quota.h3
-rw-r--r--include/linux/rio.h2
-rw-r--r--include/linux/string.h2
-rw-r--r--include/linux/sysfs.h6
-rw-r--r--include/linux/timex.h46
-rw-r--r--include/linux/usb/c67x00.h48
-rw-r--r--include/linux/usb/ch9.h12
-rw-r--r--include/linux/usb/gadget.h21
-rw-r--r--include/linux/virtio.h7
-rw-r--r--include/linux/virtio_blk.h14
-rw-r--r--include/linux/virtio_config.h81
-rw-r--r--include/linux/virtio_net.h13
-rw-r--r--include/scsi/scsi.h40
-rw-r--r--include/scsi/scsi_cmnd.h23
-rw-r--r--include/scsi/scsi_eh.h4
-rw-r--r--include/scsi/scsi_host.h8
-rw-r--r--kernel/compat.c3
-rw-r--r--kernel/exit.c1
-rw-r--r--kernel/fork.c1
-rw-r--r--kernel/irq/manage.c49
-rw-r--r--kernel/irq/spurious.c4
-rw-r--r--kernel/kexec.c2
-rw-r--r--kernel/kmod.c1
-rw-r--r--kernel/module.c319
-rw-r--r--kernel/posix-cpu-timers.c11
-rw-r--r--kernel/ptrace.c2
-rw-r--r--kernel/sched.c6
-rw-r--r--kernel/sched_debug.c4
-rw-r--r--kernel/softirq.c20
-rw-r--r--kernel/time.c54
-rw-r--r--kernel/time/ntp.c398
-rw-r--r--kernel/time/timekeeping.c17
-rw-r--r--kernel/workqueue.c6
-rw-r--r--lib/div64.c35
-rw-r--r--lib/idr.c2
-rw-r--r--lib/string.c27
-rw-r--r--mm/memcontrol.c11
-rw-r--r--mm/slub.c9
-rw-r--r--mm/vmalloc.c1
-rw-r--r--net/ipv4/tcp_cubic.c4
-rw-r--r--net/netfilter/xt_connbytes.c5
-rw-r--r--scripts/kconfig/lxdialog/check-lxdialog.sh6
-rw-r--r--security/selinux/hooks.c1
-rw-r--r--virt/kvm/kvm_main.c21
346 files changed, 12783 insertions, 3950 deletions
diff --git a/Documentation/hwmon/w83l785ts b/Documentation/hwmon/w83l785ts
index 1841cedc25b..bd1fa9d4468 100644
--- a/Documentation/hwmon/w83l785ts
+++ b/Documentation/hwmon/w83l785ts
@@ -33,7 +33,8 @@ Known Issues
------------
On some systems (Asus), the BIOS is known to interfere with the driver
-and cause read errors. The driver will retry a given number of times
+and cause read errors. Or maybe the W83L785TS-S chip is simply unreliable,
+we don't really know. The driver will retry a given number of times
(5 by default) and then give up, returning the old value (or 0 if
there is no old value). It seems to work well enough so that you should
not notice anything. Thanks to James Bolt for helping test this feature.
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
index d0ac72cc19f..b8e52c0355d 100644
--- a/Documentation/kdump/kdump.txt
+++ b/Documentation/kdump/kdump.txt
@@ -245,6 +245,8 @@ The syntax is:
crashkernel=<range1>:<size1>[,<range2>:<size2>,...][@offset]
range=start-[end]
+ 'start' is inclusive and 'end' is exclusive.
+
For example:
crashkernel=512M-2G:64M,2G-:128M
@@ -253,10 +255,11 @@ This would mean:
1) if the RAM is smaller than 512M, then don't reserve anything
(this is the "rescue" case)
- 2) if the RAM size is between 512M and 2G, then reserve 64M
+ 2) if the RAM size is between 512M and 2G (exclusive), then reserve 64M
3) if the RAM size is larger than 2G, then reserve 128M
+
Boot into System Kernel
=======================
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index 4c1fc65a8b3..3be8ab2a886 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -131,6 +131,9 @@ struct device
/* Any queues attached to this device */
struct virtqueue *vq;
+ /* Handle status being finalized (ie. feature bits stable). */
+ void (*ready)(struct device *me);
+
/* Device-specific data. */
void *priv;
};
@@ -925,24 +928,40 @@ static void enable_fd(int fd, struct virtqueue *vq)
write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
}
-/* When the Guest asks us to reset a device, it's is fairly easy. */
-static void reset_device(struct device *dev)
+/* When the Guest tells us they updated the status field, we handle it. */
+static void update_device_status(struct device *dev)
{
struct virtqueue *vq;
- verbose("Resetting device %s\n", dev->name);
- /* Clear the status. */
- dev->desc->status = 0;
+ /* This is a reset. */
+ if (dev->desc->status == 0) {
+ verbose("Resetting device %s\n", dev->name);
- /* Clear any features they've acked. */
- memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
- dev->desc->feature_len);
+ /* Clear any features they've acked. */
+ memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
+ dev->desc->feature_len);
- /* Zero out the virtqueues. */
- for (vq = dev->vq; vq; vq = vq->next) {
- memset(vq->vring.desc, 0,
- vring_size(vq->config.num, getpagesize()));
- vq->last_avail_idx = 0;
+ /* Zero out the virtqueues. */
+ for (vq = dev->vq; vq; vq = vq->next) {
+ memset(vq->vring.desc, 0,
+ vring_size(vq->config.num, getpagesize()));
+ vq->last_avail_idx = 0;
+ }
+ } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
+ warnx("Device %s configuration FAILED", dev->name);
+ } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
+ unsigned int i;
+
+ verbose("Device %s OK: offered", dev->name);
+ for (i = 0; i < dev->desc->feature_len; i++)
+ verbose(" %08x", get_feature_bits(dev)[i]);
+ verbose(", accepted");
+ for (i = 0; i < dev->desc->feature_len; i++)
+ verbose(" %08x", get_feature_bits(dev)
+ [dev->desc->feature_len+i]);
+
+ if (dev->ready)
+ dev->ready(dev);
}
}
@@ -954,9 +973,9 @@ static void handle_output(int fd, unsigned long addr)
/* Check each device and virtqueue. */
for (i = devices.dev; i; i = i->next) {
- /* Notifications to device descriptors reset the device. */
+ /* Notifications to device descriptors update device status. */
if (from_guest_phys(addr) == i->desc) {
- reset_device(i);
+ update_device_status(i);
return;
}
@@ -1170,6 +1189,7 @@ static struct device *new_device(const char *name, u16 type, int fd,
dev->handle_input = handle_input;
dev->name = name;
dev->vq = NULL;
+ dev->ready = NULL;
/* Append to device list. Prepending to a single-linked list is
* easier, but the user expects the devices to be arranged on the bus
@@ -1398,7 +1418,7 @@ 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;
+ u8 *in;
struct virtio_blk_outhdr *out;
struct iovec iov[dev->vq->vring.num];
off64_t off;
@@ -1416,7 +1436,7 @@ static bool service_io(struct device *dev)
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);
+ in = convert(&iov[out_num+in_num-1], u8);
off = out->sector * 512;
/* The block device implements "barriers", where the Guest indicates
@@ -1430,7 +1450,7 @@ static bool service_io(struct device *dev)
* It'd be nice if we supported eject, for example, but we don't. */
if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
fprintf(stderr, "Scsi commands unsupported\n");
- in->status = VIRTIO_BLK_S_UNSUPP;
+ *in = VIRTIO_BLK_S_UNSUPP;
wlen = sizeof(*in);
} else if (out->type & VIRTIO_BLK_T_OUT) {
/* Write */
@@ -1453,7 +1473,7 @@ static bool service_io(struct device *dev)
errx(1, "Write past end %llu+%u", off, ret);
}
wlen = sizeof(*in);
- in->status = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
+ *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
} else {
/* Read */
@@ -1466,10 +1486,10 @@ static bool service_io(struct device *dev)
verbose("READ from sector %llu: %i\n", out->sector, ret);
if (ret >= 0) {
wlen = sizeof(*in) + ret;
- in->status = VIRTIO_BLK_S_OK;
+ *in = VIRTIO_BLK_S_OK;
} else {
wlen = sizeof(*in);
- in->status = VIRTIO_BLK_S_IOERR;
+ *in = VIRTIO_BLK_S_IOERR;
}
}
diff --git a/Documentation/powerpc/mpc52xx-device-tree-bindings.txt b/Documentation/powerpc/mpc52xx-device-tree-bindings.txt
index cda7a7dffa6..6f12f1c79c0 100644
--- a/Documentation/powerpc/mpc52xx-device-tree-bindings.txt
+++ b/Documentation/powerpc/mpc52xx-device-tree-bindings.txt
@@ -237,6 +237,17 @@ Each GPIO controller node should have the empty property gpio-controller and
according to the bit numbers in the GPIO control registers. The second cell
is for flags which is currently unsused.
+8) FEC nodes
+The FEC node can specify one of the following properties to configure
+the MII link:
+"fsl,7-wire-mode" - An empty property that specifies the link uses 7-wire
+ mode instead of MII
+"current-speed" - Specifies that the MII should be configured for a fixed
+ speed. This property should contain two cells. The
+ first cell specifies the speed in Mbps and the second
+ should be '0' for half duplex and '1' for full duplex
+"phy-handle" - Contains a phandle to an Ethernet PHY.
+
IV - Extra Notes
================
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index 91c81db0ba7..716fcc1cafb 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,25 @@
+1 Release Date : Mon. March 10 11:02:31 PDT 2008 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Sumant Patro
+ Bo Yang
+
+2 Current Version : 00.00.03.20-RC1
+3 Older Version : 00.00.03.16
+
+1. Rollback the sense info implementation
+ Sense buffer ptr data type in the ioctl path is reverted back
+ to u32 * as in previous versions of driver.
+
+2. Fixed the driver frame count.
+ When Driver sent wrong frame count to firmware. As this
+ particular command is sent to drive, FW is seeing continuous
+ chip resets and so the command will timeout.
+
+3. Add the new controller(1078DE) support to the driver
+ and Increase the max_wait to 60 from 10 in the controller
+ operational status. With this max_wait increase, driver will
+ make sure the FW will finish the pending cmd for KDUMP case.
+
1 Release Date : Thur. Nov. 07 16:30:43 PST 2007 -
(emaild-id:megaraidlinux@lsi.com)
Sumant Patro
diff --git a/MAINTAINERS b/MAINTAINERS
index c3a533d5d38..93547d3d04b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1196,9 +1196,9 @@ S: Maintained
CPUSETS
P: Paul Jackson
-P: Simon Derr
+P: Paul Menage
M: pj@sgi.com
-M: simon.derr@bull.net
+M: menage@google.com
L: linux-kernel@vger.kernel.org
W: http://www.bullopensource.org/cpuset/
S: Supported
@@ -1557,6 +1557,14 @@ M: raisch@de.ibm.com
L: general@lists.openfabrics.org
S: Supported
+EMBEDDED LINUX
+P: Paul Gortmaker
+M: paul.gortmaker@windriver.com
+P David Woodhouse
+M: dwmw2@infradead.org
+L: linux-embedded@vger.kernel.org
+S: Maintained
+
EMULEX LPFC FC SCSI DRIVER
P: James Smart
M: james.smart@emulex.com
@@ -4043,6 +4051,12 @@ L: linux-usb@vger.kernel.org
S: Maintained
W: http://www.kroah.com/linux-usb/
+USB CYPRESS C67X00 DRIVER
+P: Peter Korsgaard
+M: jacmet@sunsite.dk
+L: linux-usb@vger.kernel.org
+S: Maintained
+
USB DAVICOM DM9601 DRIVER
P: Peter Korsgaard
M: jacmet@sunsite.dk
diff --git a/Makefile b/Makefile
index d3634cd6fe3..5cf82581953 100644
--- a/Makefile
+++ b/Makefile
@@ -794,7 +794,7 @@ endif # ifdef CONFIG_KALLSYMS
quiet_cmd_vmlinux-modpost = LD $@
cmd_vmlinux-modpost = $(LD) $(LDFLAGS) -r -o $@ \
$(vmlinux-init) --start-group $(vmlinux-main) --end-group \
- $(filter-out $(vmlinux-init) $(vmlinux-main) $(vmlinux-lds) FORCE ,$^)
+ $(filter-out $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
define rule_vmlinux-modpost
:
+$(call cmd,vmlinux-modpost)
@@ -818,7 +818,9 @@ endif
ifdef CONFIG_KALLSYMS
.tmp_vmlinux1: vmlinux.o
endif
-vmlinux.o: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE
+
+modpost-init := $(filter-out init/built-in.o, $(vmlinux-init))
+vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE
$(call if_changed_rule,vmlinux-modpost)
# The actual objects are generated when descending,
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 9fee37e2596..32ca1b92730 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -981,27 +981,18 @@ asmlinkage int
osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
struct timeval32 __user *tvp)
{
- fd_set_bits fds;
- char *bits;
- size_t size;
- long timeout;
- int ret = -EINVAL;
- struct fdtable *fdt;
- int max_fds;
-
- timeout = MAX_SCHEDULE_TIMEOUT;
+ s64 timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) {
time_t sec, usec;
if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
|| __get_user(sec, &tvp->tv_sec)
|| __get_user(usec, &tvp->tv_usec)) {
- ret = -EFAULT;
- goto out_nofds;
+ return -EFAULT;
}
if (sec < 0 || usec < 0)
- goto out_nofds;
+ return -EINVAL;
if ((unsigned long) sec < MAX_SELECT_SECONDS) {
timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
@@ -1009,60 +1000,8 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
}
}
- rcu_read_lock();
- fdt = files_fdtable(current->files);
- max_fds = fdt->max_fds;
- rcu_read_unlock();
- if (n < 0 || n > max_fds)
- goto out_nofds;
-
- /*
- * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
- * since we used fdset we need to allocate memory in units of
- * long-words.
- */
- ret = -ENOMEM;
- size = FDS_BYTES(n);
- bits = kmalloc(6 * size, GFP_KERNEL);
- if (!bits)
- goto out_nofds;
- fds.in = (unsigned long *) bits;
- fds.out = (unsigned long *) (bits + size);
- fds.ex = (unsigned long *) (bits + 2*size);
- fds.res_in = (unsigned long *) (bits + 3*size);
- fds.res_out = (unsigned long *) (bits + 4*size);
- fds.res_ex = (unsigned long *) (bits + 5*size);
-
- if ((ret = get_fd_set(n, inp->fds_bits, fds.in)) ||
- (ret = get_fd_set(n, outp->fds_bits, fds.out)) ||
- (ret = get_fd_set(n, exp->fds_bits, fds.ex)))
- goto out;
- zero_fd_set(n, fds.res_in);
- zero_fd_set(n, fds.res_out);
- zero_fd_set(n, fds.res_ex);
-
- ret = do_select(n, &fds, &timeout);
-
/* OSF does not copy back the remaining time. */
-
- if (ret < 0)
- goto out;
- if (!ret) {
- ret = -ERESTARTNOHAND;
- if (signal_pending(current))
- goto out;
- ret = 0;
- }
-
- if (set_fd_set(n, inp->fds_bits, fds.res_in) ||
- set_fd_set(n, outp->fds_bits, fds.res_out) ||
- set_fd_set(n, exp->fds_bits, fds.res_ex))
- ret = -EFAULT;
-
- out:
- kfree(bits);
- out_nofds:
- return ret;
+ return core_sys_select(n, inp, outp, exp, &timeout);
}
struct rusage32 {
diff --git a/arch/frv/mm/Makefile b/arch/frv/mm/Makefile
index fb8b1d860f4..1bca5ab8a6a 100644
--- a/arch/frv/mm/Makefile
+++ b/arch/frv/mm/Makefile
@@ -6,4 +6,4 @@ obj-y := init.o kmap.o
obj-$(CONFIG_MMU) += \
pgalloc.o highmem.o fault.o extable.o cache-page.o tlb-flush.o tlb-miss.o \
- mmu-context.o dma-alloc.o unaligned.o elf-fdpic.o
+ mmu-context.o dma-alloc.o elf-fdpic.o
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index 256a7faeda0..b763ca19ef1 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -463,7 +463,7 @@ sys32_sigsuspend (int history0, int history1, old_sigset_t mask)
current->state = TASK_INTERRUPTIBLE;
schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
return -ERESTARTNOHAND;
}
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index c7467f863c7..19709a07963 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -966,7 +966,7 @@ acpi_map_iosapics (void)
fs_initcall(acpi_map_iosapics);
#endif /* CONFIG_ACPI_NUMA */
-int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
+int __ref acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
{
int err;
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 6dee579f205..7fd18f54c05 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -183,10 +183,10 @@ void fixup_irqs(void)
{
unsigned int irq;
extern void ia64_process_pending_intr(void);
- extern void ia64_disable_timer(void);
extern volatile int time_keeper_id;
- ia64_disable_timer();
+ /* Mask ITV to disable timer */
+ ia64_set_itv(1 << 16);
/*
* Find a new timesync master
diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
index 396004e8cd1..4547a2092af 100644
--- a/arch/ia64/kernel/palinfo.c
+++ b/arch/ia64/kernel/palinfo.c
@@ -1053,7 +1053,7 @@ static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block palinfo_cpu_notifier __cpuinitdata =
+static struct notifier_block __refdata palinfo_cpu_notifier =
{
.notifier_call = palinfo_cpu_callback,
.priority = 0,
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 7fbb51e10bb..c1ad27de2dd 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -867,7 +867,7 @@ pfm_rvfree(void *mem, unsigned long size)
}
static pfm_context_t *
-pfm_context_alloc(void)
+pfm_context_alloc(int ctx_flags)
{
pfm_context_t *ctx;
@@ -878,6 +878,46 @@ pfm_context_alloc(void)
ctx = kzalloc(sizeof(pfm_context_t), GFP_KERNEL);
if (ctx) {
DPRINT(("alloc ctx @%p\n", ctx));
+
+ /*
+ * init context protection lock
+ */
+ spin_lock_init(&ctx->ctx_lock);
+
+ /*
+ * context is unloaded
+ */
+ ctx->ctx_state = PFM_CTX_UNLOADED;
+
+ /*
+ * initialization of context's flags
+ */
+ ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
+ ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
+ ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
+ /*
+ * will move to set properties
+ * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
+ */
+
+ /*
+ * init restart semaphore to locked
+ */
+ init_completion(&ctx->ctx_restart_done);
+
+ /*
+ * activation is used in SMP only
+ */
+ ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
+ SET_LAST_CPU(ctx, -1);
+
+ /*
+ * initialize notification message queue
+ */
+ ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
+ init_waitqueue_head(&ctx->ctx_msgq_wait);
+ init_waitqueue_head(&ctx->ctx_zombieq);
+
}
return ctx;
}
@@ -2165,28 +2205,21 @@ static struct dentry_operations pfmfs_dentry_operations = {
};
-static int
-pfm_alloc_fd(struct file **cfile)
+static struct file *
+pfm_alloc_file(pfm_context_t *ctx)
{
- int fd, ret = 0;
- struct file *file = NULL;
- struct inode * inode;
+ struct file *file;
+ struct inode *inode;
+ struct dentry *dentry;
char name[32];
struct qstr this;
- fd = get_unused_fd();
- if (fd < 0) return -ENFILE;
-
- ret = -ENFILE;
-
- file = get_empty_filp();
- if (!file) goto out;
-
/*
* allocate a new inode
*/
inode = new_inode(pfmfs_mnt->mnt_sb);
- if (!inode) goto out;
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode));
@@ -2199,59 +2232,28 @@ pfm_alloc_fd(struct file **cfile)
this.len = strlen(name);
this.hash = inode->i_ino;
- ret = -ENOMEM;
-
/*
* allocate a new dcache entry
*/
- file->f_path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
- if (!file->f_path.dentry) goto out;
+ dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
+ if (!dentry) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
- file->f_path.dentry->d_op = &pfmfs_dentry_operations;
+ dentry->d_op = &pfmfs_dentry_operations;
+ d_add(dentry, inode);
- d_add(file->f_path.dentry, inode);
- file->f_path.mnt = mntget(pfmfs_mnt);
- file->f_mapping = inode->i_mapping;
+ file = alloc_file(pfmfs_mnt, dentry, FMODE_READ, &pfm_file_ops);
+ if (!file) {
+ dput(dentry);
+ return ERR_PTR(-ENFILE);
+ }
- file->f_op = &pfm_file_ops;
- file->f_mode = FMODE_READ;
file->f_flags = O_RDONLY;
- file->f_pos = 0;
-
- /*
- * may have to delay until context is attached?
- */
- fd_install(fd, file);
-
- /*
- * the file structure we will use
- */
- *cfile = file;
-
- return fd;
-out:
- if (file) put_filp(file);
- put_unused_fd(fd);
- return ret;
-}
-
-static void
-pfm_free_fd(int fd, struct file *file)
-{
- struct files_struct *files = current->files;
- struct fdtable *fdt;
+ file->private_data = ctx;
- /*
- * there ie no fd_uninstall(), so we do it here
- */
- spin_lock(&files->file_lock);
- fdt = files_fdtable(files);
- rcu_assign_pointer(fdt->fd[fd], NULL);
- spin_unlock(&files->file_lock);
-
- if (file)
- put_filp(file);
- put_unused_fd(fd);
+ return file;
}
static int
@@ -2475,6 +2477,7 @@ pfm_setup_buffer_fmt(struct task_struct *task, struct file *filp, pfm_context_t
/* link buffer format and context */
ctx->ctx_buf_fmt = fmt;
+ ctx->ctx_fl_is_sampling = 1; /* assume record() is defined */
/*
* check if buffer format wants to use perfmon buffer allocation/mapping service
@@ -2669,78 +2672,45 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
{
pfarg_context_t *req = (pfarg_context_t *)arg;
struct file *filp;
+ struct path path;
int ctx_flags;
+ int fd;
int ret;
/* let's check the arguments first */
ret = pfarg_is_sane(current, req);
- if (ret < 0) return ret;
+ if (ret < 0)
+ return ret;
ctx_flags = req->ctx_flags;
ret = -ENOMEM;
- ctx = pfm_context_alloc();
- if (!ctx) goto error;
+ fd = get_unused_fd();
+ if (fd < 0)
+ return fd;
- ret = pfm_alloc_fd(&filp);
- if (ret < 0) goto error_file;
+ ctx = pfm_context_alloc(ctx_flags);
+ if (!ctx)
+ goto error;
- req->ctx_fd = ctx->ctx_fd = ret;
+ filp = pfm_alloc_file(ctx);
+ if (IS_ERR(filp)) {
+ ret = PTR_ERR(filp);
+ goto error_file;
+ }
- /*
- * attach context to file
- */
- filp->private_data = ctx;
+ req->ctx_fd = ctx->ctx_fd = fd;
/*
* does the user want to sample?
*/
if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) {
ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req);
- if (ret) goto buffer_error;
+ if (ret)
+ goto buffer_error;
}
- /*
- * init context protection lock
- */
- spin_lock_init(&ctx->ctx_lock);
-
- /*
- * context is unloaded
- */
- ctx->ctx_state = PFM_CTX_UNLOADED;
-
- /*
- * initialization of context's flags
- */
- ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
- ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
- ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */
- ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
- /*
- * will move to set properties
- * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
- */
-
- /*
- * init restart semaphore to locked
- */
- init_completion(&ctx->ctx_restart_done);
-
- /*
- * activation is used in SMP only
- */
- ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
- SET_LAST_CPU(ctx, -1);
-
- /*
- * initialize notification message queue
- */
- ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
- init_waitqueue_head(&ctx->ctx_msgq_wait);
- init_waitqueue_head(&ctx->ctx_zombieq);
-
DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n",
ctx,
ctx_flags,
@@ -2755,10 +2725,14 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
*/
pfm_reset_pmu_state(ctx);
+ fd_install(fd, filp);
+
return 0;
buffer_error:
- pfm_free_fd(ctx->ctx_fd, filp);
+ path = filp->f_path;
+ put_filp(filp);
+ path_put(&path);
if (ctx->ctx_buf_fmt) {
pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs);
@@ -2767,6 +2741,7 @@ error_file:
pfm_context_free(ctx);
error:
+ put_unused_fd(fd);
return ret;
}
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 5740296c35a..19c5a78636f 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -464,7 +464,7 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
if (!user_mode(&scr->pt))
return;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else
oldset = &current->blocked;
@@ -530,12 +530,13 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
* continue to iterate in this loop so we can deliver the SIGSEGV...
*/
if (handle_signal(signr, &ka, &info, oldset, scr)) {
- /* a signal was successfully delivered; the saved
+ /*
+ * A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
- * clear the TIF_RESTORE_SIGMASK flag */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ * clear the TS_RESTORE_SIGMASK flag.
+ */
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
return;
}
}
@@ -566,8 +567,8 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
/* if there's no signal to deliver, we just put the saved sigmask
* back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
}
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index 9a9d4c48933..983296f1c81 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -98,8 +98,33 @@ unlock_ipi_calllock(void)
spin_unlock_irq(&call_lock);
}
+static inline void
+handle_call_data(void)
+{
+ struct call_data_struct *data;
+ void (*func)(void *info);
+ void *info;
+ int wait;
+
+ /* release the 'pointer lock' */
+ data = (struct call_data_struct *)call_data;
+ func = data->func;
+ info = data->info;
+ wait = data->wait;
+
+ mb();
+ atomic_inc(&data->started);
+ /* At this point the structure may be gone unless wait is true. */
+ (*func)(info);
+
+ /* Notify the sending CPU that the task is done. */
+ mb();
+ if (wait)
+ atomic_inc(&data->finished);
+}
+
static void
-stop_this_cpu (void)
+stop_this_cpu(void)
{
/*
* Remove this CPU:
@@ -138,44 +163,21 @@ handle_IPI (int irq, void *dev_id)
ops &= ~(1 << which);
switch (which) {
- case IPI_CALL_FUNC:
- {
- struct call_data_struct *data;
- void (*func)(void *info);
- void *info;
- int wait;
-
- /* release the 'pointer lock' */
- data = (struct call_data_struct *) call_data;
- func = data->func;
- info = data->info;
- wait = data->wait;
-
- mb();
- atomic_inc(&data->started);
- /*
- * At this point the structure may be gone unless
- * wait is true.
- */
- (*func)(info);
-
- /* Notify the sending CPU that the task is done. */
- mb();
- if (wait)
- atomic_inc(&data->finished);
- }
- break;
-
- case IPI_CPU_STOP:
+ case IPI_CALL_FUNC:
+ handle_call_data();
+ break;
+
+ case IPI_CPU_STOP:
stop_this_cpu();
break;
#ifdef CONFIG_KEXEC
- case IPI_KDUMP_CPU_STOP:
+ case IPI_KDUMP_CPU_STOP:
unw_init_running(kdump_cpu_freeze, NULL);
break;
#endif
- default:
- printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
+ default:
+ printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
+ this_cpu, which);
break;
}
} while (ops);
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 48e15a51782..8c73643f2d6 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -379,11 +379,6 @@ static struct irqaction timer_irqaction = {
.name = "timer"
};
-void __devinit ia64_disable_timer(void)
-{
- ia64_set_itv(1 << 16);
-}
-
void __init
time_init (void)
{
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index abb17a613b1..26228e2d01a 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -36,9 +36,11 @@ void arch_fix_phys_package_id(int num, u32 slot)
}
EXPORT_SYMBOL_GPL(arch_fix_phys_package_id);
-int arch_register_cpu(int num)
+
+#ifdef CONFIG_HOTPLUG_CPU
+int __ref arch_register_cpu(int num)
{
-#if defined (CONFIG_ACPI) && defined (CONFIG_HOTPLUG_CPU)
+#ifdef CONFIG_ACPI
/*
* If CPEI can be re-targetted or if this is not
* CPEI target, then it is hotpluggable
@@ -47,19 +49,21 @@ int arch_register_cpu(int num)
sysfs_cpus[num].cpu.hotpluggable = 1;
map_cpu_to_node(num, node_cpuid[num].nid);
#endif
-
return register_cpu(&sysfs_cpus[num].cpu, num);
}
-
-#ifdef CONFIG_HOTPLUG_CPU
+EXPORT_SYMBOL(arch_register_cpu);
void arch_unregister_cpu(int num)
{
unregister_cpu(&sysfs_cpus[num].cpu);
unmap_cpu_from_node(num, cpu_to_node(num));
}
-EXPORT_SYMBOL(arch_register_cpu);
EXPORT_SYMBOL(arch_unregister_cpu);
+#else
+static int __init arch_register_cpu(int num)
+{
+ return register_cpu(&sysfs_cpus[num].cpu, num);
+}
#endif /*CONFIG_HOTPLUG_CPU*/
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 6df07324013..318b8110062 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1,4 +1,3 @@
-
/*
* kvm_ia64.c: Basic KVM suppport On Itanium series processors
*
@@ -431,7 +430,7 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
if (itc_diff < 0)
itc_diff = -itc_diff;
- expires = div64_64(itc_diff, cyc_per_usec);
+ expires = div64_u64(itc_diff, cyc_per_usec);
kt = ktime_set(0, 1000 * expires);
vcpu->arch.ht_active = 1;
hrtimer_start(p_ht, kt, HRTIMER_MODE_ABS);
diff --git a/arch/m32r/Makefile b/arch/m32r/Makefile
index 4072a07ebf8..469766b24e2 100644
--- a/arch/m32r/Makefile
+++ b/arch/m32r/Makefile
@@ -5,6 +5,8 @@
# architecture-specific flags and dependencies.
#
+KBUILD_DEFCONFIG := m32700ut.smp_defconfig
+
LDFLAGS :=
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
LDFLAGS_vmlinux :=
diff --git a/arch/m32r/defconfig b/arch/m32r/defconfig
deleted file mode 100644
index af3b9817911..00000000000
--- a/arch/m32r/defconfig
+++ /dev/null
@@ -1,863 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc1
-# Wed Aug 1 17:22:35 2007
-#
-CONFIG_M32R=y
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_ZONE_DMA=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_NO_IOPORT=y
-CONFIG_NO_DMA=y
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCK_KERNEL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
-CONFIG_BSD_PROCESS_ACCT=y
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=15
-# CONFIG_CPUSETS is not set
-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 is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-# CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
-# CONFIG_EPOLL is not set
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-# CONFIG_BLK_DEV_BSG is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-CONFIG_IOSCHED_DEADLINE=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
-#
-# CONFIG_PLAT_MAPPI is not set
-# CONFIG_PLAT_USRV is not set
-CONFIG_PLAT_M32700UT=y
-# CONFIG_PLAT_OPSPUT is not set
-# CONFIG_PLAT_OAKS32R is not set
-# CONFIG_PLAT_MAPPI2 is not set
-# CONFIG_PLAT_MAPPI3 is not set
-# CONFIG_PLAT_M32104UT is not set
-CONFIG_CHIP_M32700=y
-# CONFIG_CHIP_M32102 is not set
-# CONFIG_CHIP_M32104 is not set
-# CONFIG_CHIP_VDEC2 is not set
-# CONFIG_CHIP_OPSP is not set
-CONFIG_MMU=y
-CONFIG_TLB_ENTRIES=32
-CONFIG_ISA_M32R2=y
-CONFIG_ISA_DSP_LEVEL2=y
-CONFIG_ISA_DUAL_ISSUE=y
-CONFIG_BUS_CLOCK=50000000
-CONFIG_TIMER_DIVIDE=128
-# CONFIG_CPU_LITTLE_ENDIAN is not set
-CONFIG_MEMORY_START=0x08000000
-CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_NOHIGHMEM=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_SELECT_MEMORY_MODEL=y
-# CONFIG_FLATMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM_MANUAL=y
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_NEED_MULTIPLE_NODES=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
-CONFIG_VIRT_TO_BUS=y
-CONFIG_IRAM_START=0x00f00000
-CONFIG_IRAM_SIZE=0x00080000
-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_CALIBRATE_DELAY=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_PREEMPT=y
-CONFIG_SMP=y
-# CONFIG_CHIP_M32700_TS1 is not set
-CONFIG_NR_CPUS=2
-CONFIG_NODES_SHIFT=1
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_ISA is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_IP_DCCP is not set
-# CONFIG_IP_SCTP is not set
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
-# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
-# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-# CONFIG_MTD_CHAR is not set
-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=m
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_GEN_PROBE=m
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-# CONFIG_MTD_CFI_NOSWAP is not set
-CONFIG_MTD_CFI_BE_BYTE_SWAP=y
-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
-CONFIG_MTD_CFI_GEOMETRY=y
-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 is not set
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-# CONFIG_MTD_OTP is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-CONFIG_MTD_CFI_AMDSTD=m
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=m
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_PLATRAM is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLOCK2MTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-# CONFIG_MTD_NAND is not set
-# CONFIG_MTD_ONENAND is not set
-
-#
-# UBI - Unsorted block images
-#
-# CONFIG_MTD_UBI is not set
-# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=y
-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=m
-CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
-CONFIG_IDE=y
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=m
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-CONFIG_IDE_PROC_FS=y
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=m
-# CONFIG_SCSI_DMA is not set
-# CONFIG_SCSI_TGT is not set
-# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=m
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-CONFIG_CHR_DEV_SG=m
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-CONFIG_SCSI_MULTI_LUN=y
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_MD is not set
-CONFIG_NETDEVICES=y
-# CONFIG_NETDEVICES_MULTIQUEUE is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_PHYLIB is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_SMC91X=y
-# CONFIG_NE2000 is not set
-CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_WAN is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_M32R_SIO=y
-CONFIG_SERIAL_M32R_SIO_CONSOLE=y
-CONFIG_SERIAL_M32R_PLDSIO=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=y
-# CONFIG_RTC is not set
-CONFIG_DS1302=y
-# CONFIG_R3964 is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_ABITUGURU3 is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_SM501 is not set
-
-#
-# Multimedia devices
-#
-CONFIG_VIDEO_DEV=m
-CONFIG_VIDEO_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
-CONFIG_VIDEO_V4L2=y
-CONFIG_VIDEO_CAPTURE_DRIVERS=y
-# CONFIG_VIDEO_ADV_DEBUG is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-# CONFIG_VIDEO_CPIA is not set
-CONFIG_VIDEO_M32R_AR=m
-CONFIG_VIDEO_M32R_AR_M64278=m
-CONFIG_RADIO_ADAPTERS=y
-# CONFIG_DVB_CORE is not set
-CONFIG_DAB=y
-
-#
-# Graphics support
-#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
-CONFIG_FB=y
-CONFIG_FIRMWARE_EDID=y
-# CONFIG_FB_DDC is not set
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-# CONFIG_FB_SYS_FILLRECT is not set
-# CONFIG_FB_SYS_COPYAREA is not set
-# CONFIG_FB_SYS_IMAGEBLIT is not set
-# CONFIG_FB_SYS_FOPS is not set
-CONFIG_FB_DEFERRED_IO=y
-# CONFIG_FB_SVGALIB is not set
-# CONFIG_FB_MACMODES is not set
-# CONFIG_FB_BACKLIGHT is not set
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_TILEBLITTING is not set
-
-#
-# Frame buffer hardware drivers
-#
-CONFIG_FB_S1D13XXX=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-CONFIG_LOGO_M32R_CLUT224=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
-CONFIG_USB_SUPPORT=y
-# CONFIG_USB_ARCH_HAS_HCD 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
-CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
-# CONFIG_MMC_UNSAFE_RESUME is not set
-
-#
-# MMC/SD Card Drivers
-#
-CONFIG_MMC_BLOCK=y
-CONFIG_MMC_BLOCK_BOUNCE=y
-
-#
-# MMC/SD Host Controller Drivers
-#
-# CONFIG_NEW_LEDS is not set
-
-#
-# Real Time Clock
-#
-# CONFIG_RTC_CLASS is not set
-
-#
-# Userspace I/O
-#
-# CONFIG_UIO is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-# CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=y
-CONFIG_JBD_DEBUG=y
-CONFIG_FS_MBCACHE=y
-CONFIG_REISERFS_FS=m
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_REISERFS_FS_XATTR is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_BIND34 is not set
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 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=y
-CONFIG_OPROFILE=y
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_HAS_IOMEM=y
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index 41b07854fcc..15a6f36c06d 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -60,9 +60,6 @@ SECTIONS
. = ALIGN(4096);
__nosave_end = .;
- . = ALIGN(4096);
- .data.page_aligned : { *(.data.idt) }
-
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
index fd0c685a7f1..c785d07c02c 100644
--- a/arch/m68knommu/kernel/asm-offsets.c
+++ b/arch/m68knommu/kernel/asm-offsets.c
@@ -87,6 +87,7 @@ int main(void)
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+ DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
return 0;
diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68knommu/kernel/entry.S
index 1e7ea6a3e1a..f4782d2dce8 100644
--- a/arch/m68knommu/kernel/entry.S
+++ b/arch/m68knommu/kernel/entry.S
@@ -32,6 +32,7 @@
#include <asm/segment.h>
#include <asm/asm-offsets.h>
#include <asm/entry.h>
+#include <asm/unistd.h>
.text
@@ -140,3 +141,11 @@ ENTRY(sys_rt_sigreturn)
RESTORE_SWITCH_STACK
rts
+ENTRY(ret_from_user_signal)
+ moveq #__NR_sigreturn,%d0
+ trap #0
+
+ENTRY(ret_from_user_rt_signal)
+ move #__NR_rt_sigreturn,%d0
+ trap #0
+
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index d6f0200316f..03f4fe6a2fc 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -162,7 +162,7 @@ void __init setup_arch(char **cmdline_p)
printk(KERN_INFO "DragonEngine II board support by Georges Menie\n");
#endif
#ifdef CONFIG_M5235EVB
- printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)");
+ printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n");
#endif
#ifdef DEBUG
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c
index 70371378db8..bbfcae9e52b 100644
--- a/arch/m68knommu/kernel/signal.c
+++ b/arch/m68knommu/kernel/signal.c
@@ -51,6 +51,8 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+void ret_from_user_signal(void);
+void ret_from_user_rt_signal(void);
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
/*
@@ -539,10 +541,6 @@ static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
return err;
}
-static inline void push_cache (unsigned long vaddr)
-{
-}
-
static inline void *
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
{
@@ -586,16 +584,11 @@ static void setup_frame (int sig, struct k_sigaction *ka,
err |= copy_to_user (&frame->sc, &context, sizeof(context));
/* Set up to return from userspace. */
- err |= __put_user(frame->retcode, &frame->pretcode);
- /* moveq #,d0; trap #0 */
- err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
- (long *)(frame->retcode));
+ err |= __put_user((void *) ret_from_user_signal, &frame->pretcode);
if (err)
goto give_sigsegv;
- push_cache ((unsigned long) &frame->retcode);
-
/* Set up registers for signal handler */
wrusp ((unsigned long) frame);
regs->pc = (unsigned long) ka->sa.sa_handler;
@@ -655,17 +648,11 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. */
- err |= __put_user(frame->retcode, &frame->pretcode);
- /* moveq #,d0; notb d0; trap #0 */
- err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
- (long *)(frame->retcode + 0));
- err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
+ err |= __put_user((void *) ret_from_user_rt_signal, &frame->pretcode);
if (err)
goto give_sigsegv;
- push_cache ((unsigned long) &frame->retcode);
-
/* Set up registers for signal handler */
wrusp ((unsigned long) frame);
regs->pc = (unsigned long) ka->sa.sa_handler;
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index 437a061d8b9..ec9aea652e7 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -28,6 +28,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/ptrace.h>
+#include <linux/kallsyms.h>
#include <asm/setup.h>
#include <asm/fpu.h>
@@ -102,56 +103,47 @@ asmlinkage void buserr_c(struct frame *fp)
force_sig(SIGSEGV, current);
}
-
int kstack_depth_to_print = 48;
-void show_stack(struct task_struct *task, unsigned long *stack)
+static void __show_stack(struct task_struct *task, unsigned long *stack)
{
unsigned long *endstack, addr;
- extern char _start, _etext;
+ unsigned long *last_stack;
int i;
- if (!stack) {
- if (task)
- stack = (unsigned long *)task->thread.ksp;
- else
- stack = (unsigned long *)&stack;
- }
+ if (!stack)
+ stack = (unsigned long *)task->thread.ksp;
addr = (unsigned long) stack;
endstack = (unsigned long *) PAGE_ALIGN(addr);
printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
for (i = 0; i < kstack_depth_to_print; i++) {
- if (stack + 1 > endstack)
+ if (stack + 1 + i > endstack)
break;
if (i % 8 == 0)
printk("\n" KERN_EMERG " ");
- printk(" %08lx", *stack++);
+ printk(" %08lx", *(stack + i));
}
printk("\n");
- printk(KERN_EMERG "Call Trace:");
- i = 0;
- while (stack + 1 <= endstack) {
- addr = *stack++;
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
- if (((addr >= (unsigned long) &_start) &&
- (addr <= (unsigned long) &_etext))) {
- if (i % 4 == 0)
- printk("\n" KERN_EMERG " ");
- printk(" [<%08lx>]", addr);
- i++;
- }
+#ifdef CONFIG_FRAME_POINTER
+ printk(KERN_EMERG "Call Trace:\n");
+
+ last_stack = stack - 1;
+ while (stack <= endstack && stack > last_stack) {
+
+ addr = *(stack + 1);
+ printk(KERN_EMERG " [%08lx] ", addr);
+ print_symbol(KERN_CONT "%s\n", addr);
+
+ last_stack = stack;
+ stack = (unsigned long *)*stack;
}
printk("\n");
+#else
+ printk(KERN_EMERG "CONFIG_FRAME_POINTER disabled, no symbolic call trace\n");
+#endif
}
void bad_super_trap(struct frame *fp)
@@ -298,19 +290,47 @@ asmlinkage void set_esp0(unsigned long ssp)
current->thread.esp0 = ssp;
}
-
/*
* The architecture-independent backtrace generator
*/
void dump_stack(void)
{
- unsigned long stack;
+ /*
+ * We need frame pointers for this little trick, which works as follows:
+ *
+ * +------------+ 0x00
+ * | Next SP | -> 0x0c
+ * +------------+ 0x04
+ * | Caller |
+ * +------------+ 0x08
+ * | Local vars | -> our stack var
+ * +------------+ 0x0c
+ * | Next SP | -> 0x18, that is what we pass to show_stack()
+ * +------------+ 0x10
+ * | Caller |
+ * +------------+ 0x14
+ * | Local vars |
+ * +------------+ 0x18
+ * | ... |
+ * +------------+
+ */
- show_stack(current, &stack);
-}
+ unsigned long *stack;
+ stack = (unsigned long *)&stack;
+ stack++;
+ __show_stack(current, stack);
+}
EXPORT_SYMBOL(dump_stack);
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+ if (!stack && !task)
+ dump_stack();
+ else
+ __show_stack(task, stack);
+}
+
#ifdef CONFIG_M68KFPU_EMU
asmlinkage void fpemu_signal(int signal, int code, void *addr)
{
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index b44edb08e21..5592e0bf951 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -64,6 +64,7 @@ SECTIONS {
_stext = . ;
TEXT_TEXT
SCHED_TEXT
+ LOCK_TEXT
*(.text.lock)
. = ALIGN(16); /* Exception table */
@@ -73,6 +74,7 @@ SECTIONS {
*(.rodata) *(.rodata.*)
*(__vermagic) /* Kernel version magic */
+ *(__markers_strings)
*(.rodata1)
*(.rodata.str1.1)
@@ -182,6 +184,7 @@ SECTIONS {
*(COMMON)
. = ALIGN(4) ;
_ebss = . ;
+ _end = . ;
} > BSS
}
diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c
index a6692e958f6..d01a5d2b755 100644
--- a/arch/m68knommu/platform/5206e/config.c
+++ b/arch/m68knommu/platform/5206e/config.c
@@ -48,7 +48,7 @@ static struct platform_device *m5206e_devices[] __initdata = {
/***************************************************************************/
-static void __init m5206_uart_init_line(int line, int irq)
+static void __init m5206e_uart_init_line(int line, int irq)
{
if (line == 0) {
writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
index 2aca599a1ca..230bae691a7 100644
--- a/arch/m68knommu/platform/5272/config.c
+++ b/arch/m68knommu/platform/5272/config.c
@@ -139,10 +139,6 @@ void __init config_BSP(char *commandp, int size)
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0xf0004000, size);
commandp[size-1] = 0;
-#elif defined(CONFIG_MTD_KeyTechnology)
- /* Copy command line from FLASH to local buffer... */
- memcpy(commandp, (char *) 0xffe06000, size);
- commandp[size-1] = 0;
#elif defined(CONFIG_CANCam)
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0xf0010000, size);
diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c
index 036e1b73d94..dfdb5c2ed8e 100644
--- a/arch/m68knommu/platform/528x/config.c
+++ b/arch/m68knommu/platform/528x/config.c
@@ -26,9 +26,240 @@
#include <asm/mcfuart.h>
#include <asm/mcfqspi.h>
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
/***************************************************************************/
void coldfire_reset(void);
+static void coldfire_qspi_cs_control(u8 cs, u8 command);
+
+/***************************************************************************/
+
+#if defined(CONFIG_SPI)
+
+#if defined(CONFIG_WILDFIRE)
+#define SPI_NUM_CHIPSELECTS 0x02
+#define SPI_PAR_VAL 0x07 /* Enable DIN, DOUT, CLK */
+#define SPI_CS_MASK 0x18
+
+#define FLASH_BLOCKSIZE (1024*64)
+#define FLASH_NUMBLOCKS 16
+#define FLASH_TYPE "m25p80"
+
+#define M25P80_CS 0
+#define MMC_CS 1
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition stm25p_partitions[] = {
+ /* sflash */
+ [0] = {
+ .name = "stm25p80",
+ .offset = 0x00000000,
+ .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS,
+ .mask_flags = 0
+ }
+};
+
+#endif
+
+#elif defined(CONFIG_WILDFIREMOD)
+
+#define SPI_NUM_CHIPSELECTS 0x08
+#define SPI_PAR_VAL 0x07 /* Enable DIN, DOUT, CLK */
+#define SPI_CS_MASK 0x78
+
+#define FLASH_BLOCKSIZE (1024*64)
+#define FLASH_NUMBLOCKS 64
+#define FLASH_TYPE "m25p32"
+/* Reserve 1M for the kernel parition */
+#define FLASH_KERNEL_SIZE (1024 * 1024)
+
+#define M25P80_CS 5
+#define MMC_CS 6
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition stm25p_partitions[] = {
+ /* sflash */
+ [0] = {
+ .name = "kernel",
+ .offset = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS - FLASH_KERNEL_SIZE,
+ .size = FLASH_KERNEL_SIZE,
+ .mask_flags = 0
+ },
+ [1] = {
+ .name = "image",
+ .offset = 0x00000000,
+ .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS - FLASH_KERNEL_SIZE,
+ .mask_flags = 0
+ },
+ [2] = {
+ .name = "all",
+ .offset = 0x00000000,
+ .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS,
+ .mask_flags = 0
+ }
+};
+#endif
+
+#else
+#define SPI_NUM_CHIPSELECTS 0x04
+#define SPI_PAR_VAL 0x7F /* Enable DIN, DOUT, CLK, CS0 - CS4 */
+#endif
+
+#ifdef MMC_CS
+static struct coldfire_spi_chip flash_chip_info = {
+ .mode = SPI_MODE_0,
+ .bits_per_word = 16,
+ .del_cs_to_clk = 17,
+ .del_after_trans = 1,
+ .void_write_data = 0
+};
+
+static struct coldfire_spi_chip mmc_chip_info = {
+ .mode = SPI_MODE_0,
+ .bits_per_word = 16,
+ .del_cs_to_clk = 17,
+ .del_after_trans = 1,
+ .void_write_data = 0xFFFF
+};
+#endif
+
+#ifdef M25P80_CS
+static struct flash_platform_data stm25p80_platform_data = {
+ .name = "ST M25P80 SPI Flash chip",
+#ifdef CONFIG_MTD_PARTITIONS
+ .parts = stm25p_partitions,
+ .nr_parts = sizeof(stm25p_partitions) / sizeof(*stm25p_partitions),
+#endif
+ .type = FLASH_TYPE
+};
+#endif
+
+static struct spi_board_info spi_board_info[] __initdata = {
+#ifdef M25P80_CS
+ {
+ .modalias = "m25p80",
+ .max_speed_hz = 16000000,
+ .bus_num = 1,
+ .chip_select = M25P80_CS,
+ .platform_data = &stm25p80_platform_data,
+ .controller_data = &flash_chip_info
+ },
+#endif
+#ifdef MMC_CS
+ {
+ .modalias = "mmc_spi",
+ .max_speed_hz = 16000000,
+ .bus_num = 1,
+ .chip_select = MMC_CS,
+ .controller_data = &mmc_chip_info
+ }
+#endif
+};
+
+static struct coldfire_spi_master coldfire_master_info = {
+ .bus_num = 1,
+ .num_chipselect = SPI_NUM_CHIPSELECTS,
+ .irq_source = MCF5282_QSPI_IRQ_SOURCE,
+ .irq_vector = MCF5282_QSPI_IRQ_VECTOR,
+ .irq_mask = ((0x01 << MCF5282_QSPI_IRQ_SOURCE) | 0x01),
+ .irq_lp = 0x2B, /* Level 5 and Priority 3 */
+ .par_val = SPI_PAR_VAL,
+ .cs_control = coldfire_qspi_cs_control,
+};
+
+static struct resource coldfire_spi_resources[] = {
+ [0] = {
+ .name = "qspi-par",
+ .start = MCF5282_QSPI_PAR,
+ .end = MCF5282_QSPI_PAR,
+ .flags = IORESOURCE_MEM
+ },
+
+ [1] = {
+ .name = "qspi-module",
+ .start = MCF5282_QSPI_QMR,
+ .end = MCF5282_QSPI_QMR + 0x18,
+ .flags = IORESOURCE_MEM
+ },
+
+ [2] = {
+ .name = "qspi-int-level",
+ .start = MCF5282_INTC0 + MCFINTC_ICR0 + MCF5282_QSPI_IRQ_SOURCE,
+ .end = MCF5282_INTC0 + MCFINTC_ICR0 + MCF5282_QSPI_IRQ_SOURCE,
+ .flags = IORESOURCE_MEM
+ },
+
+ [3] = {
+ .name = "qspi-int-mask",
+ .start = MCF5282_INTC0 + MCFINTC_IMRL,
+ .end = MCF5282_INTC0 + MCFINTC_IMRL,
+ .flags = IORESOURCE_MEM
+ }
+};
+
+static struct platform_device coldfire_spi = {
+ .name = "spi_coldfire",
+ .id = -1,
+ .resource = coldfire_spi_resources,
+ .num_resources = ARRAY_SIZE(coldfire_spi_resources),
+ .dev = {
+ .platform_data = &coldfire_master_info,
+ }
+};
+
+static void coldfire_qspi_cs_control(u8 cs, u8 command)
+{
+ u8 cs_bit = ((0x01 << cs) << 3) & SPI_CS_MASK;
+
+#if defined(CONFIG_WILDFIRE)
+ u8 cs_mask = ~(((0x01 << cs) << 3) & SPI_CS_MASK);
+#endif
+#if defined(CONFIG_WILDFIREMOD)
+ u8 cs_mask = (cs << 3) & SPI_CS_MASK;
+#endif
+
+ /*
+ * Don't do anything if the chip select is not
+ * one of the port qs pins.
+ */
+ if (command & QSPI_CS_INIT) {
+#if defined(CONFIG_WILDFIRE)
+ MCF5282_GPIO_DDRQS |= cs_bit;
+ MCF5282_GPIO_PQSPAR &= ~cs_bit;
+#endif
+
+#if defined(CONFIG_WILDFIREMOD)
+ MCF5282_GPIO_DDRQS |= SPI_CS_MASK;
+ MCF5282_GPIO_PQSPAR &= ~SPI_CS_MASK;
+#endif
+ }
+
+ if (command & QSPI_CS_ASSERT) {
+ MCF5282_GPIO_PORTQS &= ~SPI_CS_MASK;
+ MCF5282_GPIO_PORTQS |= cs_mask;
+ } else if (command & QSPI_CS_DROP) {
+ MCF5282_GPIO_PORTQS |= SPI_CS_MASK;
+ }
+}
+
+static int __init spi_dev_init(void)
+{
+ int retval;
+
+ retval = platform_device_register(&coldfire_spi);
+ if (retval < 0)
+ return retval;
+
+ if (ARRAY_SIZE(spi_board_info))
+ retval = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+ return retval;
+}
+
+#endif /* CONFIG_SPI */
/***************************************************************************/
@@ -111,10 +342,43 @@ void mcf_autovector(unsigned int vec)
/***************************************************************************/
+#ifdef CONFIG_WILDFIRE
+void wildfire_halt(void)
+{
+ writeb(0, 0x30000007);
+ writeb(0x2, 0x30000007);
+}
+#endif
+
+#ifdef CONFIG_WILDFIREMOD
+void wildfiremod_halt(void)
+{
+ printk(KERN_INFO "WildFireMod hibernating...\n");
+
+ /* Set portE.5 to Digital IO */
+ MCF5282_GPIO_PEPAR &= ~(1 << (5 * 2));
+
+ /* Make portE.5 an output */
+ MCF5282_GPIO_DDRE |= (1 << 5);
+
+ /* Now toggle portE.5 from low to high */
+ MCF5282_GPIO_PORTE &= ~(1 << 5);
+ MCF5282_GPIO_PORTE |= (1 << 5);
+
+ printk(KERN_EMERG "Failed to hibernate. Halting!\n");
+}
+#endif
+
void __init config_BSP(char *commandp, int size)
{
mcf_disableall();
- mach_reset = coldfire_reset;
+
+#ifdef CONFIG_WILDFIRE
+ mach_halt = wildfire_halt;
+#endif
+#ifdef CONFIG_WILDFIREMOD
+ mach_halt = wildfiremod_halt;
+#endif
}
/***************************************************************************/
diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c
index 92dc862fa82..11cff6625dc 100644
--- a/arch/m68knommu/platform/5307/config.c
+++ b/arch/m68knommu/platform/5307/config.c
@@ -124,8 +124,7 @@ void __init config_BSP(char *commandp, int size)
mcf_setimr(MCFSIM_IMR_MASKALL);
#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \
- defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \
- defined(CONFIG_CLEOPATRA)
+ defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA)
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0xf0004000, size);
commandp[size-1] = 0;
diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S
index 111b66dc737..1e3c0dcbd7a 100644
--- a/arch/m68knommu/platform/coldfire/entry.S
+++ b/arch/m68knommu/platform/coldfire/entry.S
@@ -103,9 +103,26 @@ ret_from_signal:
addql #4,%sp
ret_from_exception:
+ move #0x2700,%sr /* disable intrs */
btst #5,%sp@(PT_SR) /* check if returning to kernel */
jeq Luser_return /* if so, skip resched, signals */
+#ifdef CONFIG_PREEMPT
+ movel %sp,%d1 /* get thread_info pointer */
+ andl #-THREAD_SIZE,%d1 /* at base of kernel stack */
+ movel %d1,%a0
+ movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */
+ andl #_TIF_NEED_RESCHED,%d1
+ jeq Lkernel_return
+
+ movel %a0@(TI_PREEMPTCOUNT),%d1
+ cmpl #0,%d1
+ jne Lkernel_return
+
+ pea Lkernel_return
+ jmp preempt_schedule_irq /* preempt the kernel */
+#endif
+
Lkernel_return:
moveml %sp@,%d1-%d5/%a0-%a2
lea %sp@(32),%sp /* space for 8 regs */
@@ -140,6 +157,7 @@ Lreturn:
Lwork_to_do:
movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */
+ move #0x2000,%sr /* enable intrs again */
btst #TIF_NEED_RESCHED,%d1
jne reschedule
diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c
index 77db3473dea..9fdd8bcdd21 100644
--- a/arch/mips/kernel/binfmt_elfn32.c
+++ b/arch/mips/kernel/binfmt_elfn32.c
@@ -54,6 +54,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
#include <linux/module.h>
#include <linux/elfcore.h>
#include <linux/compat.h>
+#include <linux/math64.h>
#define elf_prstatus elf_prstatus32
struct elf_prstatus32
@@ -102,8 +103,8 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
* one divide.
*/
u64 nsec = (u64)jiffies * TICK_NSEC;
- long rem;
- value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+ u32 rem;
+ value->tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
value->tv_usec = rem / NSEC_PER_USEC;
}
diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
index 08f4cd781ee..e1333d7319e 100644
--- a/arch/mips/kernel/binfmt_elfo32.c
+++ b/arch/mips/kernel/binfmt_elfo32.c
@@ -56,6 +56,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
#include <linux/module.h>
#include <linux/elfcore.h>
#include <linux/compat.h>
+#include <linux/math64.h>
#define elf_prstatus elf_prstatus32
struct elf_prstatus32
@@ -104,8 +105,8 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
* one divide.
*/
u64 nsec = (u64)jiffies * TICK_NSEC;
- long rem;
- value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+ u32 rem;
+ value->tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
value->tv_usec = rem / NSEC_PER_USEC;
}
diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c
index 2bde200d5ad..b39bdba82e0 100644
--- a/arch/mips/kernel/irixioctl.c
+++ b/arch/mips/kernel/irixioctl.c
@@ -27,33 +27,6 @@ struct irix_termios {
cc_t c_cc[NCCS];
};
-extern void start_tty(struct tty_struct *tty);
-static struct tty_struct *get_tty(int fd)
-{
- struct file *filp;
- struct tty_struct *ttyp = NULL;
-
- rcu_read_lock();
- filp = fcheck(fd);
- if(filp && filp->private_data) {
- ttyp = (struct tty_struct *) filp->private_data;
-
- if(ttyp->magic != TTY_MAGIC)
- ttyp =NULL;
- }
- rcu_read_unlock();
- return ttyp;
-}
-
-static struct tty_struct *get_real_tty(struct tty_struct *tp)
-{
- if (tp->driver->type == TTY_DRIVER_TYPE_PTY &&
- tp->driver->subtype == PTY_TYPE_MASTER)
- return tp->link;
- else
- return tp;
-}
-
asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg)
{
struct tty_struct *tp, *rtp;
@@ -146,34 +119,24 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg)
error = sys_ioctl(fd, TIOCNOTTY, arg);
break;
- case 0x00007416:
+ case 0x00007416: {
+ pid_t pid;
#ifdef DEBUG_IOCTLS
printk("TIOCGSID, %08lx) ", arg);
#endif
- tp = get_tty(fd);
- if(!tp) {
- error = -EINVAL;
- break;
- }
- rtp = get_real_tty(tp);
-#ifdef DEBUG_IOCTLS
- printk("rtp->session=%d ", rtp->session);
-#endif
- error = put_user(rtp->session, (unsigned long __user *) arg);
+ old_fs = get_fs(); set_fs(get_ds());
+ error = sys_ioctl(fd, TIOCGSID, (unsigned long)&pid);
+ set_fs(old_fs);
+ if (!error)
+ error = put_user(pid, (unsigned long __user *) arg);
break;
-
+ }
case 0x746e:
/* TIOCSTART, same effect as hitting ^Q */
#ifdef DEBUG_IOCTLS
printk("TIOCSTART, %08lx) ", arg);
#endif
- tp = get_tty(fd);
- if(!tp) {
- error = -EINVAL;
- break;
- }
- rtp = get_real_tty(tp);
- start_tty(rtp);
+ error = sys_ioctl(fd, TCXONC, TCOON);
break;
case 0x20006968:
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index 998c4efcce8..ceb62dce1c9 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -20,6 +20,7 @@
#include <linux/sched.h>
#include <linux/unistd.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/syscalls.h>
#include <linux/workqueue.h>
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index 1f2f1e0a557..bba234eb14a 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -21,6 +21,7 @@
serial1 = &serial1;
pci0 = &pci0;
pci1 = &pci1;
+ pci2 = &pci2;
};
cpus {
@@ -105,7 +106,7 @@
compatible = "ns16550";
reg = <0x4600 0x100>;
clock-frequency = <0>;
- interrupts = <28 2>;
+ interrupts = <42 2>;
interrupt-parent = <&mpic>;
};
@@ -322,4 +323,24 @@
};
};
};
+
+ pci2: pcie@e0009000 {
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ device_type = "pci";
+ compatible = "fsl,mpc8641-pcie";
+ reg = <0xe0009000 0x00001000>;
+ ranges = <0x02000000 0 0x90000000 0x90000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xe2000000 0 0x00100000>;
+ bus-range = <0 255>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <0x0000 0 0 1 &mpic 4 1
+ 0x0000 0 0 2 &mpic 5 1
+ 0x0000 0 0 3 &mpic 6 1
+ 0x0000 0 0 4 &mpic 7 1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <25 2>;
+ clock-frequency = <33333333>;
+ };
};
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index 7a64c564f6e..71d79e428d2 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.25-rc6
-# Thu Mar 20 11:07:04 2008
+# Linux kernel version: 2.6.25
+# Mon Apr 28 12:39:10 2008
#
CONFIG_PPC64=y
@@ -30,6 +30,9 @@ CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_ARCH_HAS_ILOG2_U64=y
@@ -73,8 +76,6 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=17
# CONFIG_CGROUPS is not set
# CONFIG_GROUP_SCHED is not set
-# CONFIG_USER_SCHED is not set
-# CONFIG_CGROUP_SCHED is not set
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_RELAY is not set
@@ -161,7 +162,6 @@ CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
# CONFIG_PPC_PASEMI is not set
-# CONFIG_PPC_CELLEB is not set
CONFIG_PPC_PS3=y
#
@@ -181,6 +181,7 @@ CONFIG_PS3_LPM=m
CONFIG_PPC_CELL=y
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_IBM_CELL_BLADE is not set
+# CONFIG_PPC_CELLEB is not set
#
# Cell Broadband Engine options
@@ -205,9 +206,9 @@ CONFIG_SPU_BASE=y
#
# Kernel options
#
-# CONFIG_TICK_ONESHOT is not set
+CONFIG_TICK_ONESHOT=y
# CONFIG_NO_HZ is not set
-# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
@@ -221,7 +222,6 @@ CONFIG_PREEMPT_NONE=y
CONFIG_BINFMT_ELF=y
CONFIG_COMPAT_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
-CONFIG_FORCE_MAX_ZONEORDER=13
# CONFIG_IOMMU_VMERGE is not set
CONFIG_IOMMU_HELPER=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
@@ -255,6 +255,7 @@ CONFIG_BOUNCE=y
CONFIG_ARCH_MEMORY_PROBE=y
# CONFIG_PPC_HAS_HASH_64K is not set
# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
# CONFIG_SCHED_SMT is not set
CONFIG_PROC_DEVICETREE=y
# CONFIG_CMDLINE_BOOL is not set
@@ -272,7 +273,9 @@ CONFIG_GENERIC_ISA_DMA=y
# CONFIG_PCI_SYSCALL is not set
# CONFIG_ARCH_SUPPORTS_MSI is not set
# CONFIG_PCCARD is not set
+CONFIG_PAGE_OFFSET=0xc000000000000000
CONFIG_KERNEL_START=0xc000000000000000
+CONFIG_PHYSICAL_START=0x00000000
#
# Networking
@@ -292,7 +295,7 @@ CONFIG_XFRM=y
# CONFIG_XFRM_STATISTICS is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
@@ -301,6 +304,7 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
@@ -332,8 +336,10 @@ 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_NDISC_NODETYPE=y
# CONFIG_IPV6_TUNNEL is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
@@ -392,8 +398,6 @@ CONFIG_IEEE80211=m
CONFIG_IEEE80211_CRYPT_WEP=m
CONFIG_IEEE80211_CRYPT_CCMP=m
CONFIG_IEEE80211_CRYPT_TKIP=m
-CONFIG_IEEE80211_SOFTMAC=m
-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -507,6 +511,7 @@ CONFIG_WLAN_80211=y
# CONFIG_LIBERTAS is not set
# CONFIG_USB_ZD1201 is not set
# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_IWLWIFI_LEDS is not set
# CONFIG_HOSTAP is not set
#
@@ -578,6 +583,7 @@ CONFIG_INPUT_JOYSTICK=y
# CONFIG_JOYSTICK_SPACEBALL is not set
# CONFIG_JOYSTICK_STINGER is not set
# CONFIG_JOYSTICK_TWIDJOY is not set
+# CONFIG_JOYSTICK_ZHENHUA is not set
# CONFIG_JOYSTICK_JOYDUMP is not set
# CONFIG_JOYSTICK_XPAD is not set
# CONFIG_INPUT_TABLET is not set
@@ -641,6 +647,7 @@ CONFIG_SSB_POSSIBLE=y
# Multifunction device drivers
#
# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
#
# Multimedia devices
@@ -761,10 +768,6 @@ CONFIG_SND_PS3_DEFAULT_START_DELAY=2000
# CONFIG_SND_SOC is not set
#
-# SoC Audio support for SuperH
-#
-
-#
# ALSA SoC audio for Freescale SOCs
#
@@ -849,6 +852,7 @@ CONFIG_USB_STORAGE=m
# CONFIG_USB_STORAGE_ALAUDA is not set
# CONFIG_USB_STORAGE_ONETOUCH is not set
# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
# CONFIG_USB_LIBUSUAL is not set
#
@@ -893,10 +897,6 @@ CONFIG_USB_MON=y
# CONFIG_EDAC is not set
# CONFIG_RTC_CLASS is not set
# CONFIG_DMADEVICES is not set
-
-#
-# Userspace I/O
-#
# CONFIG_UIO is not set
#
@@ -986,7 +986,6 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
-# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
@@ -1059,9 +1058,10 @@ CONFIG_NLS_ISO8859_1=y
# Library routines
#
CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC_ITU_T=m
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
@@ -1071,6 +1071,7 @@ CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
#
# Kernel hacking
@@ -1078,6 +1079,7 @@ CONFIG_HAS_DMA=y
# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
@@ -1093,12 +1095,16 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_RT_MUTEX_TESTER is not set
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
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
CONFIG_DEBUG_LIST=y
# CONFIG_DEBUG_SG is not set
# CONFIG_BOOT_PRINTK_DELAY is not set
@@ -1121,51 +1127,81 @@ CONFIG_IRQSTACKS=y
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_AEAD=m
CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_SEQIV=m
CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_GF128MUL=m
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
-CONFIG_CRYPTO_GF128MUL=m
-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_CTR=m
-CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_CCM=m
-# CONFIG_CRYPTO_CRYPTD is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_SEED is not set
CONFIG_CRYPTO_SALSA20=m
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
# CONFIG_CRYPTO_DEFLATE is not set
-CONFIG_CRYPTO_MICHAEL_MIC=m
-# 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_LZO=m
CONFIG_CRYPTO_HW=y
# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index be35ffae10f..1457aa0a08f 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -386,6 +386,8 @@ static void __init smp_create_idle(unsigned int cpu)
panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
#ifdef CONFIG_PPC64
paca[cpu].__current = p;
+ paca[cpu].kstack = (unsigned long) task_thread_info(p)
+ + THREAD_SIZE - STACK_FRAME_OVERHEAD;
#endif
current_set[cpu] = task_thread_info(p);
task_thread_info(p)->cpu = cpu;
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 3b26fbd6bec..73401e83739 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -149,7 +149,7 @@ EXPORT_SYMBOL(tb_ticks_per_sec); /* for cputime_t conversions */
u64 tb_to_xs;
unsigned tb_to_us;
-#define TICKLEN_SCALE TICK_LENGTH_SHIFT
+#define TICKLEN_SCALE NTP_SCALE_SHIFT
u64 last_tick_len; /* units are ns / 2^TICKLEN_SCALE */
u64 ticklen_to_xs; /* 0.64 fraction */
@@ -1007,8 +1007,6 @@ void __init time_init(void)
vdso_data->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;
vdso_data->tb_to_xs = tb_to_xs;
- time_freq = 0;
-
write_sequnlock_irqrestore(&xtime_lock, flags);
/* Register the clocksource, if we're not running on iSeries */
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 906daeda59a..cf8705e32d6 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -30,7 +30,7 @@
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
#else
-#define DBG(fmt...)
+#define DBG pr_debug
#endif
extern void slb_allocate_realmode(unsigned long ea);
@@ -44,13 +44,13 @@ static void slb_allocate(unsigned long ea)
slb_allocate_realmode(ea);
}
+#define slb_esid_mask(ssize) \
+ (((ssize) == MMU_SEGSIZE_256M)? ESID_MASK: ESID_MASK_1T)
+
static inline unsigned long mk_esid_data(unsigned long ea, int ssize,
unsigned long slot)
{
- unsigned long mask;
-
- mask = (ssize == MMU_SEGSIZE_256M)? ESID_MASK: ESID_MASK_1T;
- return (ea & mask) | SLB_ESID_V | slot;
+ return (ea & slb_esid_mask(ssize)) | SLB_ESID_V | slot;
}
#define slb_vsid_shift(ssize) \
@@ -279,8 +279,8 @@ void slb_initialize(void)
patch_slb_encoding(slb_compare_rr_to_size,
mmu_slb_size);
- DBG("SLB: linear LLP = %04x\n", linear_llp);
- DBG("SLB: io LLP = %04x\n", io_llp);
+ DBG("SLB: linear LLP = %04lx\n", linear_llp);
+ DBG("SLB: io LLP = %04lx\n", io_llp);
}
get_paca()->stab_rr = SLB_NUM_BOLTED;
@@ -301,11 +301,16 @@ void slb_initialize(void)
create_shadowed_slbe(VMALLOC_START, mmu_kernel_ssize, vflags, 1);
+ /* For the boot cpu, we're running on the stack in init_thread_union,
+ * which is in the first segment of the linear mapping, and also
+ * get_paca()->kstack hasn't been initialized yet.
+ * For secondary cpus, we need to bolt the kernel stack entry now.
+ */
slb_shadow_clear(2);
+ if (raw_smp_processor_id() != boot_cpuid &&
+ (get_paca()->kstack & slb_esid_mask(mmu_kernel_ssize)) > PAGE_OFFSET)
+ create_shadowed_slbe(get_paca()->kstack,
+ mmu_kernel_ssize, lflags, 2);
- /* We don't bolt the stack for the time being - we're in boot,
- * so the stack is in the bolted segment. By the time it goes
- * elsewhere, we'll call _switch() which will bolt in the new
- * one. */
asm volatile("isync":::"memory");
}
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index b962c3ab470..af116aadba1 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -22,6 +22,7 @@
#include <linux/elf.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/module.h>
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index a14e5cdc2fe..e59634f7af9 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -167,8 +167,8 @@ static struct irq_chip ps3_irq_chip = {
* ps3_private data.
*/
-int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
- unsigned int *virq)
+static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
+ unsigned int *virq)
{
int result;
struct ps3_private *pd;
@@ -217,7 +217,7 @@ fail_create:
* Clears chip data and calls irq_dispose_mapping() for the virq.
*/
-int ps3_virq_destroy(unsigned int virq)
+static int ps3_virq_destroy(unsigned int virq)
{
const struct ps3_private *pd = get_irq_chip_data(virq);
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 3d920376f58..a0fa4ebb39c 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -176,6 +176,7 @@ struct rio_priv {
/**
* fsl_rio_doorbell_send - Send a MPC85xx doorbell message
+ * @mport: RapidIO master port info
* @index: ID of RapidIO interface
* @destid: Destination ID of target device
* @data: 16-bit info field of RapidIO doorbell message
@@ -211,6 +212,7 @@ static int fsl_rio_doorbell_send(struct rio_mport *mport,
/**
* fsl_local_config_read - Generate a MPC85xx local config space read
+ * @mport: RapidIO master port info
* @index: ID of RapdiIO interface
* @offset: Offset into configuration space
* @len: Length (in bytes) of the maintenance transaction
@@ -232,6 +234,7 @@ static int fsl_local_config_read(struct rio_mport *mport,
/**
* fsl_local_config_write - Generate a MPC85xx local config space write
+ * @mport: RapidIO master port info
* @index: ID of RapdiIO interface
* @offset: Offset into configuration space
* @len: Length (in bytes) of the maintenance transaction
@@ -254,6 +257,7 @@ static int fsl_local_config_write(struct rio_mport *mport,
/**
* fsl_rio_config_read - Generate a MPC85xx read maintenance transaction
+ * @mport: RapidIO master port info
* @index: ID of RapdiIO interface
* @destid: Destination ID of transaction
* @hopcount: Number of hops to target device
@@ -295,6 +299,7 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
/**
* fsl_rio_config_write - Generate a MPC85xx write maintenance transaction
+ * @mport: RapidIO master port info
* @index: ID of RapdiIO interface
* @destid: Destination ID of transaction
* @hopcount: Number of hops to target device
@@ -985,8 +990,8 @@ static inline void fsl_rio_info(struct device *dev, u32 ccsr)
}
/**
- * fsl_rio_setup - Setup MPC85xx RapidIO interface
- * @fsl_rio_setup - Setup Freescale PowerPC RapidIO interface
+ * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface
+ * @dev: of_device pointer
*
* Initializes MPC85xx RapidIO hardware interface, configures
* master port with system-specific info, and registers the
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 324c01b70dd..3a7054e2bb7 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -389,8 +389,8 @@ static int __init gfar_of_init(void)
}
gfar_data.phy_id = *id;
- snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%x",
- res.start);
+ snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%llx",
+ (unsigned long long)res.start);
of_node_put(phy);
of_node_put(mdio);
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index ba8eea2bcce..b7aefd0d45c 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -107,7 +107,7 @@ xilinx_intc_init(struct device_node *np)
}
regs = ioremap(res.start, 32);
- printk(KERN_INFO "Xilinx intc at 0x%08X mapped to 0x%p\n",
+ printk(KERN_INFO "Xilinx intc at 0x%08LX mapped to 0x%p\n",
res.start, regs);
/* Setup interrupt controller */
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 3c13137685d..8a55c4f0df8 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -180,11 +180,9 @@ static void __init boot_flags_init(char *commands)
/* This routine will in the future do all the nasty prom stuff
* to probe for the mmu type and its parameters, etc. This will
- * also be where SMP things happen plus the Sparc specific memory
- * physical memory probe as on the alpha.
+ * also be where SMP things happen.
*/
-extern int prom_probe_memory(void);
extern void sun4c_probe_vac(void);
extern char cputypval;
extern unsigned long start, end;
@@ -268,7 +266,6 @@ void __init setup_arch(char **cmdline_p)
if (ARCH_SUN4C_SUN4)
sun4c_probe_vac();
load_mmu();
- (void) prom_probe_memory();
phys_base = 0xffffffffUL;
highest_paddr = 0UL;
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index e4d9c8e19df..abd50795a7b 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -47,64 +47,15 @@ int vac_size, vac_linesize, vac_do_hw_vac_flushes;
int vac_entries_per_context, vac_entries_per_segment;
int vac_entries_per_page;
-/* Nice, simple, prom library does all the sweating for us. ;) */
-int prom_probe_memory (void)
+/* Return how much physical memory we have. */
+unsigned long probe_memory(void)
{
- register struct linux_mlist_v0 *mlist;
- register unsigned long bytes, base_paddr, tally;
- register int i;
-
- i = 0;
- mlist= *prom_meminfo()->v0_available;
- bytes = tally = mlist->num_bytes;
- base_paddr = (unsigned long) mlist->start_adr;
-
- sp_banks[0].base_addr = base_paddr;
- sp_banks[0].num_bytes = bytes;
-
- while (mlist->theres_more != (void *) 0){
- i++;
- mlist = mlist->theres_more;
- bytes = mlist->num_bytes;
- tally += bytes;
- if (i > SPARC_PHYS_BANKS-1) {
- printk ("The machine has more banks than "
- "this kernel can support\n"
- "Increase the SPARC_PHYS_BANKS "
- "setting (currently %d)\n",
- SPARC_PHYS_BANKS);
- i = SPARC_PHYS_BANKS-1;
- break;
- }
-
- sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
- sp_banks[i].num_bytes = mlist->num_bytes;
- }
-
- i++;
- sp_banks[i].base_addr = 0xdeadbeef;
- sp_banks[i].num_bytes = 0;
-
- /* Now mask all bank sizes on a page boundary, it is all we can
- * use anyways.
- */
- for(i=0; sp_banks[i].num_bytes != 0; i++)
- sp_banks[i].num_bytes &= PAGE_MASK;
-
- return tally;
-}
-
-/* Traverse the memory lists in the prom to see how much physical we
- * have.
- */
-unsigned long
-probe_memory(void)
-{
- int total;
+ unsigned long total = 0;
+ int i;
- total = prom_probe_memory();
+ for (i = 0; sp_banks[i].num_bytes; i++)
+ total += sp_banks[i].num_bytes;
- /* Oh man, much nicer, keep the dirt in promlib. */
return total;
}
diff --git a/arch/sparc/prom/init.c b/arch/sparc/prom/init.c
index 50abfb1b880..2fa3a474e3a 100644
--- a/arch/sparc/prom/init.c
+++ b/arch/sparc/prom/init.c
@@ -21,8 +21,6 @@ linux_sun4_romvec *sun4_romvec;
/* The root node of the prom device tree. */
int prom_root_node;
-int prom_stdin, prom_stdout;
-
/* Pointer to the device tree operations structure. */
struct linux_nodeops *prom_nodeops;
@@ -74,11 +72,6 @@ void __init prom_init(struct linux_romvec *rp)
(((unsigned long) prom_nodeops) == -1))
prom_halt();
- if(prom_vers == PROM_V2 || prom_vers == PROM_V3) {
- prom_stdout = *romvec->pv_v2bootargs.fd_stdout;
- prom_stdin = *romvec->pv_v2bootargs.fd_stdin;
- }
-
prom_meminit();
prom_ranges_init();
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
index b0c0f9c4fc1..947f047dc95 100644
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -1,215 +1,100 @@
-/* $Id: memory.c,v 1.15 2000/01/29 01:09:12 anton Exp $
- * memory.c: Prom routine for acquiring various bits of information
+/* memory.c: Prom routine for acquiring various bits of information
* about RAM on the machine, both virtual and physical.
*
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2008 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
*/
#include <linux/kernel.h>
+#include <linux/sort.h>
#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/sun4prom.h>
#include <asm/oplib.h>
+#include <asm/page.h>
-/* This routine, for consistency, returns the ram parameters in the
- * V0 prom memory descriptor format. I choose this format because I
- * think it was the easiest to work with. I feel the religious
- * arguments now... ;) Also, I return the linked lists sorted to
- * prevent paging_init() upset stomach as I have not yet written
- * the pepto-bismol kernel module yet.
- */
+static int __init prom_meminit_v0(void)
+{
+ struct linux_mlist_v0 *p;
+ int index;
+
+ index = 0;
+ for (p = *(romvec->pv_v0mem.v0_available); p; p = p->theres_more) {
+ sp_banks[index].base_addr = (unsigned long) p->start_adr;
+ sp_banks[index].num_bytes = p->num_bytes;
+ index++;
+ }
-struct linux_prom_registers prom_reg_memlist[64];
-struct linux_prom_registers prom_reg_tmp[64];
+ return index;
+}
-struct linux_mlist_v0 prom_phys_total[64];
-struct linux_mlist_v0 prom_prom_taken[64];
-struct linux_mlist_v0 prom_phys_avail[64];
+static int __init prom_meminit_v2(void)
+{
+ struct linux_prom_registers reg[64];
+ int node, size, num_ents, i;
-struct linux_mlist_v0 *prom_ptot_ptr = prom_phys_total;
-struct linux_mlist_v0 *prom_ptak_ptr = prom_prom_taken;
-struct linux_mlist_v0 *prom_pavl_ptr = prom_phys_avail;
+ node = prom_searchsiblings(prom_getchild(prom_root_node), "memory");
+ size = prom_getproperty(node, "available", (char *) reg, sizeof(reg));
+ num_ents = size / sizeof(struct linux_prom_registers);
-struct linux_mem_v0 prom_memlist;
+ for (i = 0; i < num_ents; i++) {
+ sp_banks[i].base_addr = reg[i].phys_addr;
+ sp_banks[i].num_bytes = reg[i].reg_size;
+ }
+ return num_ents;
+}
-/* Internal Prom library routine to sort a linux_mlist_v0 memory
- * list. Used below in initialization.
- */
-static void __init
-prom_sortmemlist(struct linux_mlist_v0 *thislist)
+static int __init prom_meminit_sun4(void)
{
- int swapi = 0;
- int i, mitr, tmpsize;
- char *tmpaddr;
- char *lowest;
-
- for(i=0; thislist[i].theres_more; i++) {
- lowest = thislist[i].start_adr;
- for(mitr = i+1; thislist[mitr-1].theres_more; mitr++)
- if(thislist[mitr].start_adr < lowest) {
- lowest = thislist[mitr].start_adr;
- swapi = mitr;
- }
- if(lowest == thislist[i].start_adr) continue;
- tmpaddr = thislist[swapi].start_adr;
- tmpsize = thislist[swapi].num_bytes;
- for(mitr = swapi; mitr > i; mitr--) {
- thislist[mitr].start_adr = thislist[mitr-1].start_adr;
- thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
- }
- thislist[i].start_adr = tmpaddr;
- thislist[i].num_bytes = tmpsize;
- }
+#ifdef CONFIG_SUN4
+ sp_banks[0].base_addr = 0;
+ sp_banks[0].num_bytes = *(sun4_romvec->memoryavail);
+#endif
+ return 1;
+}
+
+static int sp_banks_cmp(const void *a, const void *b)
+{
+ const struct sparc_phys_banks *x = a, *y = b;
- return;
+ if (x->base_addr > y->base_addr)
+ return 1;
+ if (x->base_addr < y->base_addr)
+ return -1;
+ return 0;
}
/* Initialize the memory lists based upon the prom version. */
void __init prom_meminit(void)
{
- int node = 0;
- unsigned int iter, num_regs;
- struct linux_mlist_v0 *mptr; /* ptr for traversal */
+ int i, num_ents = 0;
- switch(prom_vers) {
+ switch (prom_vers) {
case PROM_V0:
- /* Nice, kind of easier to do in this case. */
- /* First, the total physical descriptors. */
- for(mptr = (*(romvec->pv_v0mem.v0_totphys)), iter=0;
- mptr; mptr=mptr->theres_more, iter++) {
- prom_phys_total[iter].start_adr = mptr->start_adr;
- prom_phys_total[iter].num_bytes = mptr->num_bytes;
- prom_phys_total[iter].theres_more = &prom_phys_total[iter+1];
- }
- prom_phys_total[iter-1].theres_more = NULL;
- /* Second, the total prom taken descriptors. */
- for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0;
- mptr; mptr=mptr->theres_more, iter++) {
- prom_prom_taken[iter].start_adr = mptr->start_adr;
- prom_prom_taken[iter].num_bytes = mptr->num_bytes;
- prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1];
- }
- prom_prom_taken[iter-1].theres_more = NULL;
- /* Last, the available physical descriptors. */
- for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0;
- mptr; mptr=mptr->theres_more, iter++) {
- prom_phys_avail[iter].start_adr = mptr->start_adr;
- prom_phys_avail[iter].num_bytes = mptr->num_bytes;
- prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1];
- }
- prom_phys_avail[iter-1].theres_more = NULL;
- /* Sort all the lists. */
- prom_sortmemlist(prom_phys_total);
- prom_sortmemlist(prom_prom_taken);
- prom_sortmemlist(prom_phys_avail);
+ num_ents = prom_meminit_v0();
break;
+
case PROM_V2:
case PROM_V3:
- /* Grrr, have to traverse the prom device tree ;( */
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(node, "memory");
- num_regs = prom_getproperty(node, "available",
- (char *) prom_reg_memlist,
- sizeof(prom_reg_memlist));
- num_regs = (num_regs/sizeof(struct linux_prom_registers));
- for(iter=0; iter<num_regs; iter++) {
- prom_phys_avail[iter].start_adr =
- (char *) prom_reg_memlist[iter].phys_addr;
- prom_phys_avail[iter].num_bytes =
- (unsigned long) prom_reg_memlist[iter].reg_size;
- prom_phys_avail[iter].theres_more =
- &prom_phys_avail[iter+1];
- }
- prom_phys_avail[iter-1].theres_more = NULL;
-
- num_regs = prom_getproperty(node, "reg",
- (char *) prom_reg_memlist,
- sizeof(prom_reg_memlist));
- num_regs = (num_regs/sizeof(struct linux_prom_registers));
- for(iter=0; iter<num_regs; iter++) {
- prom_phys_total[iter].start_adr =
- (char *) prom_reg_memlist[iter].phys_addr;
- prom_phys_total[iter].num_bytes =
- (unsigned long) prom_reg_memlist[iter].reg_size;
- prom_phys_total[iter].theres_more =
- &prom_phys_total[iter+1];
- }
- prom_phys_total[iter-1].theres_more = NULL;
-
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(node, "virtual-memory");
- num_regs = prom_getproperty(node, "available",
- (char *) prom_reg_memlist,
- sizeof(prom_reg_memlist));
- num_regs = (num_regs/sizeof(struct linux_prom_registers));
-
- /* Convert available virtual areas to taken virtual
- * areas. First sort, then convert.
- */
- for(iter=0; iter<num_regs; iter++) {
- prom_prom_taken[iter].start_adr =
- (char *) prom_reg_memlist[iter].phys_addr;
- prom_prom_taken[iter].num_bytes =
- (unsigned long) prom_reg_memlist[iter].reg_size;
- prom_prom_taken[iter].theres_more =
- &prom_prom_taken[iter+1];
- }
- prom_prom_taken[iter-1].theres_more = NULL;
-
- prom_sortmemlist(prom_prom_taken);
-
- /* Finally, convert. */
- for(iter=0; iter<num_regs; iter++) {
- prom_prom_taken[iter].start_adr =
- prom_prom_taken[iter].start_adr +
- prom_prom_taken[iter].num_bytes;
- prom_prom_taken[iter].num_bytes =
- prom_prom_taken[iter+1].start_adr -
- prom_prom_taken[iter].start_adr;
- }
- prom_prom_taken[iter-1].num_bytes =
- 0xffffffff - (unsigned long) prom_prom_taken[iter-1].start_adr;
-
- /* Sort the other two lists. */
- prom_sortmemlist(prom_phys_total);
- prom_sortmemlist(prom_phys_avail);
+ num_ents = prom_meminit_v2();
break;
case PROM_SUN4:
-#ifdef CONFIG_SUN4
- /* how simple :) */
- prom_phys_total[0].start_adr = NULL;
- prom_phys_total[0].num_bytes = *(sun4_romvec->memorysize);
- prom_phys_total[0].theres_more = NULL;
- prom_prom_taken[0].start_adr = NULL;
- prom_prom_taken[0].num_bytes = 0x0;
- prom_prom_taken[0].theres_more = NULL;
- prom_phys_avail[0].start_adr = NULL;
- prom_phys_avail[0].num_bytes = *(sun4_romvec->memoryavail);
- prom_phys_avail[0].theres_more = NULL;
-#endif
+ num_ents = prom_meminit_sun4();
break;
default:
break;
- };
-
- /* Link all the lists into the top-level descriptor. */
- prom_memlist.v0_totphys=&prom_ptot_ptr;
- prom_memlist.v0_prommap=&prom_ptak_ptr;
- prom_memlist.v0_available=&prom_pavl_ptr;
+ }
+ sort(sp_banks, num_ents, sizeof(struct sparc_phys_banks),
+ sp_banks_cmp, NULL);
- return;
-}
+ /* Sentinel. */
+ sp_banks[num_ents].base_addr = 0xdeadbeef;
+ sp_banks[num_ents].num_bytes = 0;
-/* This returns a pointer to our libraries internal v0 format
- * memory descriptor.
- */
-struct linux_mem_v0 *
-prom_meminfo(void)
-{
- return &prom_memlist;
+ for (i = 0; i < num_ents; i++)
+ sp_banks[i].num_bytes &= PAGE_MASK;
}
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index dbf2fc2f4d8..112b09f16f3 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -350,8 +350,7 @@ static void pci_parse_of_addrs(struct of_device *op,
struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
struct device_node *node,
- struct pci_bus *bus, int devfn,
- int host_controller)
+ struct pci_bus *bus, int devfn)
{
struct dev_archdata *sd;
struct pci_dev *dev;
@@ -390,43 +389,28 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
dev->devfn = devfn;
dev->multifunction = 0; /* maybe a lie? */
- if (host_controller) {
- if (tlb_type != hypervisor) {
- pci_read_config_word(dev, PCI_VENDOR_ID,
- &dev->vendor);
- pci_read_config_word(dev, PCI_DEVICE_ID,
- &dev->device);
- } else {
- dev->vendor = PCI_VENDOR_ID_SUN;
- dev->device = 0x80f0;
- }
- dev->cfg_size = 256;
- dev->class = PCI_CLASS_BRIDGE_HOST << 8;
- sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
- 0x00, PCI_SLOT(devfn), PCI_FUNC(devfn));
- } else {
- dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
- dev->device = of_getintprop_default(node, "device-id", 0xffff);
- dev->subsystem_vendor =
- of_getintprop_default(node, "subsystem-vendor-id", 0);
- dev->subsystem_device =
- of_getintprop_default(node, "subsystem-id", 0);
-
- dev->cfg_size = pci_cfg_space_size(dev);
-
- /* We can't actually use the firmware value, we have
- * to read what is in the register right now. One
- * reason is that in the case of IDE interfaces the
- * firmware can sample the value before the the IDE
- * interface is programmed into native mode.
- */
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
- dev->class = class >> 8;
- dev->revision = class & 0xff;
+ dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
+ dev->device = of_getintprop_default(node, "device-id", 0xffff);
+ dev->subsystem_vendor =
+ of_getintprop_default(node, "subsystem-vendor-id", 0);
+ dev->subsystem_device =
+ of_getintprop_default(node, "subsystem-id", 0);
+
+ dev->cfg_size = pci_cfg_space_size(dev);
+
+ /* We can't actually use the firmware value, we have
+ * to read what is in the register right now. One
+ * reason is that in the case of IDE interfaces the
+ * firmware can sample the value before the the IDE
+ * interface is programmed into native mode.
+ */
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+ dev->class = class >> 8;
+ dev->revision = class & 0xff;
+
+ sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
+ dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
- sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
- dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
- }
if (ofpci_verbose)
printk(" class: 0x%x device name: %s\n",
dev->class, pci_name(dev));
@@ -441,26 +425,21 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
dev->current_state = 4; /* unknown power state */
dev->error_state = pci_channel_io_normal;
- if (host_controller) {
+ if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
+ /* a PCI-PCI bridge */
dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
dev->rom_base_reg = PCI_ROM_ADDRESS1;
- dev->irq = PCI_IRQ_NONE;
+ } else if (!strcmp(type, "cardbus")) {
+ dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
} else {
- if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
- /* a PCI-PCI bridge */
- dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
- dev->rom_base_reg = PCI_ROM_ADDRESS1;
- } else if (!strcmp(type, "cardbus")) {
- dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
- } else {
- dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
- dev->rom_base_reg = PCI_ROM_ADDRESS;
+ dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
+ dev->rom_base_reg = PCI_ROM_ADDRESS;
- dev->irq = sd->op->irqs[0];
- if (dev->irq == 0xffffffff)
- dev->irq = PCI_IRQ_NONE;
- }
+ dev->irq = sd->op->irqs[0];
+ if (dev->irq == 0xffffffff)
+ dev->irq = PCI_IRQ_NONE;
}
+
pci_parse_of_addrs(sd->op, node, dev);
if (ofpci_verbose)
@@ -749,7 +728,7 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
prev_devfn = devfn;
/* create a new pci_dev for this device */
- dev = of_create_pci_dev(pbm, child, bus, devfn, 0);
+ dev = of_create_pci_dev(pbm, child, bus, devfn);
if (!dev)
continue;
if (ofpci_verbose)
@@ -796,48 +775,9 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
pci_bus_register_of_sysfs(child_bus);
}
-int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
- unsigned int devfn,
- int where, int size,
- u32 *value)
-{
- static u8 fake_pci_config[] = {
- 0x8e, 0x10, /* Vendor: 0x108e (Sun) */
- 0xf0, 0x80, /* Device: 0x80f0 (Fire) */
- 0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */
- 0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */
- 0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */
- 0x00, /* Cacheline: 0x00 */
- 0x40, /* Latency: 0x40 */
- 0x00, /* Header-Type: 0x00 normal */
- };
-
- *value = 0;
- if (where >= 0 && where < sizeof(fake_pci_config) &&
- (where + size) >= 0 &&
- (where + size) < sizeof(fake_pci_config) &&
- size <= sizeof(u32)) {
- while (size--) {
- *value <<= 8;
- *value |= fake_pci_config[where + size];
- }
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
- unsigned int devfn,
- int where, int size,
- u32 value)
-{
- return PCIBIOS_SUCCESSFUL;
-}
-
struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
{
struct device_node *node = pbm->prom_node;
- struct pci_dev *host_pdev;
struct pci_bus *bus;
printk("PCI: Scanning PBM %s\n", node->full_name);
@@ -855,10 +795,6 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
bus->resource[0] = &pbm->io_space;
bus->resource[1] = &pbm->mem_space;
- /* Create the dummy host bridge and link it in. */
- host_pdev = of_create_pci_dev(pbm, node, bus, 0x00, 1);
- bus->self = host_pdev;
-
pci_of_scan_bus(pbm, node, bus);
pci_bus_add_devices(bus);
pci_bus_register_of_sysfs(bus);
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 923e0bcc3bf..19fa621d6a6 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -264,9 +264,6 @@ static int sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
unsigned int func = PCI_FUNC(devfn);
unsigned long ret;
- if (!bus && devfn == 0x00)
- return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
- size, value);
if (config_out_of_range(pbm, bus, devfn, where)) {
ret = ~0UL;
} else {
@@ -300,9 +297,6 @@ static int sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
unsigned int func = PCI_FUNC(devfn);
unsigned long ret;
- if (!bus && devfn == 0x00)
- return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
- size, value);
if (config_out_of_range(pbm, bus, devfn, where)) {
/* Do nothing. */
} else {
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 218bac4ff79..c385d126be1 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -167,15 +167,6 @@ extern void pci_get_pbm_props(struct pci_pbm_info *pbm);
extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
-extern int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
- unsigned int devfn,
- int where, int size,
- u32 *value);
-extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
- unsigned int devfn,
- int where, int size,
- u32 value);
-
/* Error reporting support. */
extern void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *);
extern void pci_scan_for_master_abort(struct pci_pbm_info *, struct pci_bus *);
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 05601374915..500ac6d483a 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -591,12 +591,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
if (clone_flags & CLONE_SETTLS)
t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];
- /* We do not want to accidently trigger system call restart
- * handling in the new thread. Therefore, clear out the trap
- * type, which will make pt_regs_regs_is_syscall() return false.
- */
- pt_regs_clear_trap_type(t->kregs);
-
return 0;
}
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index f2d88d8f7a4..45d6bf632da 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -332,6 +332,9 @@ void do_rt_sigreturn(struct pt_regs *regs)
regs->tpc = tpc;
regs->tnpc = tnpc;
+ /* Prevent syscall restart. */
+ pt_regs_clear_trap_type(regs);
+
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
current->blocked = set;
@@ -515,7 +518,8 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
siginfo_t info;
int signr;
- if (pt_regs_is_syscall(regs)) {
+ if (pt_regs_is_syscall(regs) &&
+ (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
pt_regs_clear_trap_type(regs);
cookie.restart_syscall = 1;
} else
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 91f8d0826db..9415d2c918c 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -268,6 +268,9 @@ void do_sigreturn32(struct pt_regs *regs)
regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
regs->tstate |= psr_to_tstate_icc(psr);
+ /* Prevent syscall restart. */
+ pt_regs_clear_trap_type(regs);
+
err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
err |= restore_fpu_state32(regs, &sf->fpu_state);
@@ -351,6 +354,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
regs->tstate |= psr_to_tstate_icc(psr);
+ /* Prevent syscall restart. */
+ pt_regs_clear_trap_type(regs);
+
err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
err |= restore_fpu_state32(regs, &sf->fpu_state);
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 361e3161127..4c943eabacc 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -35,7 +35,7 @@
#include "i8254.h"
#ifndef CONFIG_X86_64
-#define mod_64(x, y) ((x) - (y) * div64_64(x, y))
+#define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
#else
#define mod_64(x, y) ((x) % (y))
#endif
@@ -60,8 +60,8 @@ static u64 muldiv64(u64 a, u32 b, u32 c)
rl = (u64)u.l.low * (u64)b;
rh = (u64)u.l.high * (u64)b;
rh += (rl >> 32);
- res.l.high = div64_64(rh, c);
- res.l.low = div64_64(((mod_64(rh, c) << 32) + (rl & 0xffffffff)), c);
+ res.l.high = div64_u64(rh, c);
+ res.l.low = div64_u64(((mod_64(rh, c) << 32) + (rl & 0xffffffff)), c);
return res.ll;
}
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 57ac4e4c556..36809d79788 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -25,13 +25,13 @@
#include <linux/hrtimer.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/math64.h>
#include <asm/processor.h>
#include <asm/msr.h>
#include <asm/page.h>
#include <asm/current.h>
#include <asm/apicdef.h>
#include <asm/atomic.h>
-#include <asm/div64.h>
#include "irq.h"
#define PRId64 "d"
@@ -526,8 +526,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
} else
passed = ktime_sub(now, apic->timer.last_update);
- counter_passed = div64_64(ktime_to_ns(passed),
- (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
+ counter_passed = div64_u64(ktime_to_ns(passed),
+ (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
if (counter_passed > tmcct) {
if (unlikely(!apic_lvtt_period(apic))) {
diff --git a/block/blk-barrier.c b/block/blk-barrier.c
index 66e55288178..a09ead19f9c 100644
--- a/block/blk-barrier.c
+++ b/block/blk-barrier.c
@@ -26,8 +26,7 @@ int blk_queue_ordered(struct request_queue *q, unsigned ordered,
{
if (ordered & (QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_POSTFLUSH) &&
prepare_flush_fn == NULL) {
- printk(KERN_ERR "%s: prepare_flush_fn required\n",
- __FUNCTION__);
+ printk(KERN_ERR "%s: prepare_flush_fn required\n", __func__);
return -EINVAL;
}
diff --git a/block/blk-core.c b/block/blk-core.c
index 5d09f8c5602..b754a4a2f9b 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -136,7 +136,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
if (unlikely(nbytes > bio->bi_size)) {
printk(KERN_ERR "%s: want %u bytes done, %u left\n",
- __FUNCTION__, nbytes, bio->bi_size);
+ __func__, nbytes, bio->bi_size);
nbytes = bio->bi_size;
}
@@ -1566,8 +1566,7 @@ static int __end_that_request_first(struct request *req, int error,
if (unlikely(bio->bi_idx >= bio->bi_vcnt)) {
blk_dump_rq_flags(req, "__end_that");
printk(KERN_ERR "%s: bio idx %d >= vcnt %d\n",
- __FUNCTION__, bio->bi_idx,
- bio->bi_vcnt);
+ __func__, bio->bi_idx, bio->bi_vcnt);
break;
}
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 6089384ab06..bb93d4c3277 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -168,8 +168,8 @@ void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors)
{
if ((max_sectors << 9) < PAGE_CACHE_SIZE) {
max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
- printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
- max_sectors);
+ printk(KERN_INFO "%s: set to minimum %d\n",
+ __func__, max_sectors);
}
if (BLK_DEF_MAX_SECTORS > max_sectors)
@@ -196,8 +196,8 @@ void blk_queue_max_phys_segments(struct request_queue *q,
{
if (!max_segments) {
max_segments = 1;
- printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
- max_segments);
+ printk(KERN_INFO "%s: set to minimum %d\n",
+ __func__, max_segments);
}
q->max_phys_segments = max_segments;
@@ -220,8 +220,8 @@ void blk_queue_max_hw_segments(struct request_queue *q,
{
if (!max_segments) {
max_segments = 1;
- printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
- max_segments);
+ printk(KERN_INFO "%s: set to minimum %d\n",
+ __func__, max_segments);
}
q->max_hw_segments = max_segments;
@@ -241,8 +241,8 @@ void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size)
{
if (max_size < PAGE_CACHE_SIZE) {
max_size = PAGE_CACHE_SIZE;
- printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
- max_size);
+ printk(KERN_INFO "%s: set to minimum %d\n",
+ __func__, max_size);
}
q->max_segment_size = max_size;
@@ -357,8 +357,8 @@ void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask)
{
if (mask < PAGE_CACHE_SIZE - 1) {
mask = PAGE_CACHE_SIZE - 1;
- printk(KERN_INFO "%s: set to minimum %lx\n", __FUNCTION__,
- mask);
+ printk(KERN_INFO "%s: set to minimum %lx\n",
+ __func__, mask);
}
q->seg_boundary_mask = mask;
diff --git a/block/blk-tag.c b/block/blk-tag.c
index e176ddbe599..de64e042997 100644
--- a/block/blk-tag.c
+++ b/block/blk-tag.c
@@ -112,7 +112,7 @@ init_tag_map(struct request_queue *q, struct blk_queue_tag *tags, int depth)
if (q && depth > q->nr_requests * 2) {
depth = q->nr_requests * 2;
printk(KERN_ERR "%s: adjusted depth to %d\n",
- __FUNCTION__, depth);
+ __func__, depth);
}
tag_index = kzalloc(depth * sizeof(struct request *), GFP_ATOMIC);
@@ -296,13 +296,13 @@ void blk_queue_end_tag(struct request_queue *q, struct request *rq)
if (unlikely(bqt->tag_index[tag] == NULL))
printk(KERN_ERR "%s: tag %d is missing\n",
- __FUNCTION__, tag);
+ __func__, tag);
bqt->tag_index[tag] = NULL;
if (unlikely(!test_bit(tag, bqt->tag_map))) {
printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n",
- __FUNCTION__, tag);
+ __func__, tag);
return;
}
/*
@@ -340,7 +340,7 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
if (unlikely((rq->cmd_flags & REQ_QUEUED))) {
printk(KERN_ERR
"%s: request %p for device [%s] already tagged %d",
- __FUNCTION__, rq,
+ __func__, rq,
rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->tag);
BUG();
}
diff --git a/block/bsg.c b/block/bsg.c
index 23ea4fd1a66..f0b7cd34321 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -57,7 +57,7 @@ enum {
#undef BSG_DEBUG
#ifdef BSG_DEBUG
-#define dprintk(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ##args)
+#define dprintk(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ##args)
#else
#define dprintk(fmt, args...)
#endif
@@ -174,7 +174,11 @@ unlock:
static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
struct sg_io_v4 *hdr, int has_write_perm)
{
- memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
+ if (hdr->request_len > BLK_MAX_CDB) {
+ rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
+ if (!rq->cmd)
+ return -ENOMEM;
+ }
if (copy_from_user(rq->cmd, (void *)(unsigned long)hdr->request,
hdr->request_len))
@@ -211,8 +215,6 @@ bsg_validate_sgv4_hdr(struct request_queue *q, struct sg_io_v4 *hdr, int *rw)
if (hdr->guard != 'Q')
return -EINVAL;
- if (hdr->request_len > BLK_MAX_CDB)
- return -EINVAL;
if (hdr->dout_xfer_len > (q->max_sectors << 9) ||
hdr->din_xfer_len > (q->max_sectors << 9))
return -EIO;
@@ -302,6 +304,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr)
}
return rq;
out:
+ if (rq->cmd != rq->__cmd)
+ kfree(rq->cmd);
blk_put_request(rq);
if (next_rq) {
blk_rq_unmap_user(next_rq->bio);
@@ -455,6 +459,8 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
ret = rq->errors;
blk_rq_unmap_user(bio);
+ if (rq->cmd != rq->__cmd)
+ kfree(rq->cmd);
blk_put_request(rq);
return ret;
diff --git a/block/elevator.c b/block/elevator.c
index ac5310ef827..980f8ae147b 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -650,7 +650,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
default:
printk(KERN_ERR "%s: bad insertion point %d\n",
- __FUNCTION__, where);
+ __func__, where);
BUG();
}
@@ -808,8 +808,7 @@ struct request *elv_next_request(struct request_queue *q)
rq->cmd_flags |= REQ_QUIET;
end_queued_request(rq, 0);
} else {
- printk(KERN_ERR "%s: bad return=%d\n", __FUNCTION__,
- ret);
+ printk(KERN_ERR "%s: bad return=%d\n", __func__, ret);
break;
}
}
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index ffa3720e6ca..78199c08ec9 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -33,13 +33,12 @@
#include <scsi/scsi_cmnd.h>
/* Command group 3 is reserved and should never be used. */
-const unsigned char scsi_command_size[8] =
+const unsigned char scsi_command_size_tbl[8] =
{
6, 10, 10, 12,
16, 12, 10, 10
};
-
-EXPORT_SYMBOL(scsi_command_size);
+EXPORT_SYMBOL(scsi_command_size_tbl);
#include <scsi/sg.h>
diff --git a/crypto/authenc.c b/crypto/authenc.c
index ed8ac5a6fa5..4b226768752 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -217,9 +217,10 @@ static void crypto_authenc_givencrypt_done(struct crypto_async_request *req,
int err)
{
if (!err) {
- struct aead_givcrypt_request *greq = req->data;
+ struct aead_request *areq = req->data;
+ struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
- err = crypto_authenc_genicv(&greq->areq, greq->giv, 0);
+ err = crypto_authenc_genicv(areq, greq->giv, 0);
}
aead_request_complete(req->data, err);
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index 250425263e0..b150de56205 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -190,8 +190,10 @@ static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg,
int err;
inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
- if (IS_ERR(inst))
+ if (!inst) {
+ inst = ERR_PTR(-ENOMEM);
goto out;
+ }
err = -ENAMETOOLONG;
if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c
index b14f14e314b..881d3091043 100644
--- a/crypto/eseqiv.c
+++ b/crypto/eseqiv.c
@@ -136,7 +136,8 @@ static int eseqiv_givencrypt(struct skcipher_givcrypt_request *req)
}
ablkcipher_request_set_crypt(subreq, reqctx->src, dst,
- req->creq.nbytes, req->creq.info);
+ req->creq.nbytes + ivsize,
+ req->creq.info);
memcpy(req->creq.info, ctx->salt, ivsize);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 6fe41742997..e38dfed41d8 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -18,7 +18,7 @@ struct sysdev_class cpu_sysdev_class = {
};
EXPORT_SYMBOL(cpu_sysdev_class);
-static struct sys_device *cpu_sys_devices[NR_CPUS];
+static DEFINE_PER_CPU(struct sys_device *, cpu_sys_devices);
#ifdef CONFIG_HOTPLUG_CPU
static ssize_t show_online(struct sys_device *dev, char *buf)
@@ -68,7 +68,7 @@ void unregister_cpu(struct cpu *cpu)
sysdev_remove_file(&cpu->sysdev, &attr_online);
sysdev_unregister(&cpu->sysdev);
- cpu_sys_devices[logical_cpu] = NULL;
+ per_cpu(cpu_sys_devices, logical_cpu) = NULL;
return;
}
#else /* ... !CONFIG_HOTPLUG_CPU */
@@ -167,7 +167,7 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
if (!error && cpu->hotpluggable)
register_cpu_control(cpu);
if (!error)
- cpu_sys_devices[num] = &cpu->sysdev;
+ per_cpu(cpu_sys_devices, num) = &cpu->sysdev;
if (!error)
register_cpu_under_node(num, cpu_to_node(num));
@@ -180,8 +180,8 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
struct sys_device *get_cpu_sysdev(unsigned cpu)
{
- if (cpu < NR_CPUS)
- return cpu_sys_devices[cpu];
+ if (cpu < nr_cpu_ids && cpu_possible(cpu))
+ return per_cpu(cpu_sys_devices, cpu);
else
return NULL;
}
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index e539be5750d..e336b05fe4a 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -428,13 +428,9 @@ static void __devinit cciss_procinit(int i)
proc_cciss = proc_mkdir("driver/cciss", NULL);
if (!proc_cciss)
return;
- pde = proc_create(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP |
+ pde = proc_create_data(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP |
S_IROTH, proc_cciss,
- &cciss_proc_fops);
- if (!pde)
- return;
-
- pde->data = hba[i];
+ &cciss_proc_fops, hba[i]);
}
#endif /* CONFIG_PROC_FS */
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index e322cce8c12..3a281ef11ff 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -205,6 +205,7 @@ struct ub_scsi_cmd {
unsigned char key, asc, ascq; /* May be valid if error==-EIO */
int stat_count; /* Retries getting status. */
+ unsigned int timeo; /* jiffies until rq->timeout changes */
unsigned int len; /* Requested length */
unsigned int current_sg;
@@ -318,6 +319,7 @@ struct ub_dev {
int openc; /* protected by ub_lock! */
/* kref is too implicit for our taste */
int reset; /* Reset is running */
+ int bad_resid;
unsigned int tagcnt;
char name[12];
struct usb_device *dev;
@@ -764,6 +766,12 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
cmd->cdb_len = rq->cmd_len;
cmd->len = rq->data_len;
+
+ /*
+ * To reapply this to every URB is not as incorrect as it looks.
+ * In return, we avoid any complicated tracking calculations.
+ */
+ cmd->timeo = rq->timeout;
}
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
@@ -785,10 +793,6 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
scsi_status = 0;
} else {
if (cmd->act_len != cmd->len) {
- if ((cmd->key == MEDIUM_ERROR ||
- cmd->key == UNIT_ATTENTION) &&
- ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
- return;
scsi_status = SAM_STAT_CHECK_CONDITION;
} else {
scsi_status = 0;
@@ -804,7 +808,10 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
else
scsi_status = DID_ERROR << 16;
} else {
- if (cmd->error == -EIO) {
+ if (cmd->error == -EIO &&
+ (cmd->key == 0 ||
+ cmd->key == MEDIUM_ERROR ||
+ cmd->key == UNIT_ATTENTION)) {
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
return;
}
@@ -1259,14 +1266,19 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return;
}
- len = le32_to_cpu(bcs->Residue);
- if (len != cmd->len - cmd->act_len) {
- /*
- * It is all right to transfer less, the caller has
- * to check. But it's not all right if the device
- * counts disagree with our counts.
- */
- goto Bad_End;
+ if (!sc->bad_resid) {
+ len = le32_to_cpu(bcs->Residue);
+ if (len != cmd->len - cmd->act_len) {
+ /*
+ * Only start ignoring if this cmd ended well.
+ */
+ if (cmd->len == cmd->act_len) {
+ printk(KERN_NOTICE "%s: "
+ "bad residual %d of %d, ignoring\n",
+ sc->name, len, cmd->len);
+ sc->bad_resid = 1;
+ }
+ }
}
switch (bcs->Status) {
@@ -1297,8 +1309,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
ub_state_done(sc, cmd, -EIO);
} else {
- printk(KERN_WARNING "%s: "
- "wrong command state %d\n",
+ printk(KERN_WARNING "%s: wrong command state %d\n",
sc->name, cmd->state);
ub_state_done(sc, cmd, -EINVAL);
return;
@@ -1336,7 +1347,10 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return;
}
- sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
+ if (cmd->timeo)
+ sc->work_timer.expires = jiffies + cmd->timeo;
+ else
+ sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
add_timer(&sc->work_timer);
cmd->state = UB_CMDST_DATA;
@@ -1376,7 +1390,10 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return -1;
}
- sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
+ if (cmd->timeo)
+ sc->work_timer.expires = jiffies + cmd->timeo;
+ else
+ sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
add_timer(&sc->work_timer);
return 0;
}
@@ -1515,8 +1532,7 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
return;
}
if (cmd->state != UB_CMDST_SENSE) {
- printk(KERN_WARNING "%s: "
- "sense done with bad cmd state %d\n",
+ printk(KERN_WARNING "%s: sense done with bad cmd state %d\n",
sc->name, cmd->state);
return;
}
@@ -1720,7 +1736,7 @@ static int ub_bd_ioctl(struct inode *inode, struct file *filp,
}
/*
- * This is called once a new disk was seen by the block layer or by ub_probe().
+ * This is called by check_disk_change if we reported a media change.
* The main onjective here is to discover the features of the media such as
* the capacity, read-only status, etc. USB storage generally does not
* need to be spun up, but if we needed it, this would be the place.
@@ -2136,8 +2152,7 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
}
if (ep_in == NULL || ep_out == NULL) {
- printk(KERN_NOTICE "%s: failed endpoint check\n",
- sc->name);
+ printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name);
return -ENODEV;
}
@@ -2354,7 +2369,7 @@ static void ub_disconnect(struct usb_interface *intf)
spin_unlock_irqrestore(&ub_lock, flags);
/*
- * Fence stall clearnings, operations triggered by unlinkings and so on.
+ * Fence stall clearings, operations triggered by unlinkings and so on.
* We do not attempt to unlink any URBs, because we do not trust the
* unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
*/
@@ -2417,7 +2432,7 @@ static void ub_disconnect(struct usb_interface *intf)
spin_unlock_irqrestore(sc->lock, flags);
/*
- * There is virtually no chance that other CPU runs times so long
+ * There is virtually no chance that other CPU runs a timeout so long
* after ub_urb_complete should have called del_timer, but only if HCD
* didn't forget to deliver a callback on unlink.
*/
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 0cfbe8c594a..84e064ffee5 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -35,7 +35,7 @@ struct virtblk_req
struct list_head list;
struct request *req;
struct virtio_blk_outhdr out_hdr;
- struct virtio_blk_inhdr in_hdr;
+ u8 status;
};
static void blk_done(struct virtqueue *vq)
@@ -48,7 +48,7 @@ static void blk_done(struct virtqueue *vq)
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) {
+ switch (vbr->status) {
case VIRTIO_BLK_S_OK:
uptodate = 1;
break;
@@ -101,7 +101,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
sg_init_table(vblk->sg, VIRTIO_MAX_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));
+ sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
if (rq_data_dir(vbr->req) == WRITE) {
vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
@@ -157,10 +157,25 @@ static int virtblk_ioctl(struct inode *inode, struct file *filp,
/* We provide getgeo only to please some old bootloader/partitioning tools */
static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
{
- /* some standard values, similar to sd */
- geo->heads = 1 << 6;
- geo->sectors = 1 << 5;
- geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+ struct virtio_blk *vblk = bd->bd_disk->private_data;
+ struct virtio_blk_geometry vgeo;
+ int err;
+
+ /* see if the host passed in geometry config */
+ err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY,
+ offsetof(struct virtio_blk_config, geometry),
+ &vgeo);
+
+ if (!err) {
+ geo->heads = vgeo.heads;
+ geo->sectors = vgeo.sectors;
+ geo->cylinders = vgeo.cylinders;
+ } else {
+ /* some standard values, similar to sd */
+ geo->heads = 1 << 6;
+ geo->sectors = 1 << 5;
+ geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+ }
return 0;
}
@@ -242,12 +257,12 @@ static int virtblk_probe(struct virtio_device *vdev)
index++;
/* If barriers are supported, tell block layer that queue is ordered */
- if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER))
+ if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
/* Host must always specify the capacity. */
- __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity),
- &cap);
+ vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
+ &cap, sizeof(cap));
/* If capacity is too big, truncate with warning. */
if ((sector_t)cap != cap) {
@@ -289,7 +304,6 @@ out:
static void virtblk_remove(struct virtio_device *vdev)
{
struct virtio_blk *vblk = vdev->priv;
- int major = vblk->disk->major;
/* Nothing should be pending. */
BUG_ON(!list_empty(&vblk->reqs));
@@ -299,7 +313,6 @@ static void virtblk_remove(struct virtio_device *vdev)
blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk);
- unregister_blkdev(major, "virtblk");
mempool_destroy(vblk->pool);
vdev->config->del_vq(vblk->vq);
kfree(vblk);
@@ -310,7 +323,14 @@ static struct virtio_device_id id_table[] = {
{ 0 },
};
+static unsigned int features[] = {
+ VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
+ VIRTIO_BLK_F_GEOMETRY,
+};
+
static struct virtio_driver virtio_blk = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index f49037b744f..b60d425ce8d 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -77,6 +77,10 @@ static int power_status;
module_param(power_status, bool, 0600);
MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
+static int fan_mult = I8K_FAN_MULT;
+module_param(fan_mult, int, 0);
+MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
+
static int i8k_open_fs(struct inode *inode, struct file *file);
static int i8k_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
@@ -239,7 +243,7 @@ static int i8k_get_fan_speed(int fan)
struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
regs.ebx = fan & 0xff;
- return i8k_smm(&regs) ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
+ return i8k_smm(&regs) ? : (regs.eax & 0xffff) * fan_mult;
}
/*
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index d83db5d880e..192961fd717 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -30,6 +30,8 @@
#include <linux/miscdevice.h>
#include <linux/posix-timers.h>
#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/math64.h>
#include <asm/uaccess.h>
#include <asm/sn/addrs.h>
@@ -472,8 +474,8 @@ static int sgi_clock_get(clockid_t clockid, struct timespec *tp)
nsec = rtc_time() * sgi_clock_period
+ sgi_clock_offset.tv_nsec;
- tp->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tp->tv_nsec)
- + sgi_clock_offset.tv_sec;
+ *tp = ns_to_timespec(nsec);
+ tp->tv_sec += sgi_clock_offset.tv_sec;
return 0;
};
@@ -481,11 +483,11 @@ static int sgi_clock_set(clockid_t clockid, struct timespec *tp)
{
u64 nsec;
- u64 rem;
+ u32 rem;
nsec = rtc_time() * sgi_clock_period;
- sgi_clock_offset.tv_sec = tp->tv_sec - div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+ sgi_clock_offset.tv_sec = tp->tv_sec - div_u64_rem(nsec, NSEC_PER_SEC, &rem);
if (rem <= tp->tv_nsec)
sgi_clock_offset.tv_nsec = tp->tv_sec - rem;
@@ -644,9 +646,6 @@ static int sgi_timer_del(struct k_itimer *timr)
return 0;
}
-#define timespec_to_ns(x) ((x).tv_nsec + (x).tv_sec * NSEC_PER_SEC)
-#define ns_to_timespec(ts, nsec) (ts).tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &(ts).tv_nsec)
-
/* Assumption: it_lock is already held with irq's disabled */
static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
{
@@ -659,9 +658,8 @@ static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
return;
}
- ns_to_timespec(cur_setting->it_interval, timr->it.mmtimer.incr * sgi_clock_period);
- ns_to_timespec(cur_setting->it_value, (timr->it.mmtimer.expires - rtc_time())* sgi_clock_period);
- return;
+ cur_setting->it_interval = ns_to_timespec(timr->it.mmtimer.incr * sgi_clock_period);
+ cur_setting->it_value = ns_to_timespec((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period);
}
@@ -679,8 +677,8 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
sgi_timer_get(timr, old_setting);
sgi_timer_del(timr);
- when = timespec_to_ns(new_setting->it_value);
- period = timespec_to_ns(new_setting->it_interval);
+ when = timespec_to_ns(&new_setting->it_value);
+ period = timespec_to_ns(&new_setting->it_interval);
if (when == 0)
/* Clear timer */
@@ -695,7 +693,7 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
unsigned long now;
getnstimeofday(&n);
- now = timespec_to_ns(n);
+ now = timespec_to_ns(&n);
if (when > now)
when -= now;
else
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 513b7c2f3e2..ac5080df256 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -2028,13 +2028,13 @@ static void mgsl_change_params(struct mgsl_struct *info)
*/
static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+ struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
- int ret;
+ int ret = 0;
- if ( debug_level >= DEBUG_LEVEL_INFO ) {
- printk( "%s(%d):mgsl_put_char(%d) on %s\n",
- __FILE__,__LINE__,ch,info->device_name);
+ if (debug_level >= DEBUG_LEVEL_INFO) {
+ printk(KERN_DEBUG "%s(%d):mgsl_put_char(%d) on %s\n",
+ __FILE__, __LINE__, ch, info->device_name);
}
if (mgsl_paranoia_check(info, tty->name, "mgsl_put_char"))
@@ -2043,9 +2043,9 @@ static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
if (!tty || !info->xmit_buf)
return 0;
- spin_lock_irqsave(&info->irq_spinlock,flags);
+ spin_lock_irqsave(&info->irq_spinlock, flags);
- if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) {
+ if ((info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active) {
if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) {
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= SERIAL_XMIT_SIZE-1;
@@ -2053,7 +2053,7 @@ static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
ret = 1;
}
}
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
+ spin_unlock_irqrestore(&info->irq_spinlock, flags);
return ret;
} /* end of mgsl_put_char() */
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
index 6342b0534f4..3582f43345a 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/char/tty_audit.c
@@ -11,6 +11,7 @@
#include <linux/audit.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/tty.h>
struct tty_audit_buf {
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 1d298c2cf93..49c1a2267a5 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -78,6 +78,7 @@
#include <linux/tty_flip.h>
#include <linux/devpts_fs.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/console.h>
#include <linux/timer.h>
#include <linux/ctype.h>
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index dfe6907ae15..3edf1fc1296 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -623,8 +623,8 @@ static int __devinit hwicap_setup(struct device *dev, int id,
if (!request_mem_region(drvdata->mem_start,
drvdata->mem_size, DRIVER_NAME)) {
- dev_err(dev, "Couldn't lock memory region at %p\n",
- (void *)regs_res->start);
+ dev_err(dev, "Couldn't lock memory region at %Lx\n",
+ regs_res->start);
retval = -EBUSY;
goto failed1;
}
@@ -643,7 +643,7 @@ static int __devinit hwicap_setup(struct device *dev, int id,
mutex_init(&drvdata->sem);
drvdata->is_open = 0;
- dev_info(dev, "ioremap %lx to %p with size %x\n",
+ dev_info(dev, "ioremap %lx to %p with size %Lx\n",
(unsigned long int)drvdata->mem_start,
drvdata->base_address, drvdata->mem_size);
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 2a999373863..b2458bb8e9c 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -784,7 +784,7 @@ static void sbp2_release_target(struct kref *kref)
kfree(lu);
}
scsi_remove_host(shost);
- fw_notify("released %s\n", tgt->bus_id);
+ fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no);
fw_unit_put(tgt->unit);
scsi_host_put(shost);
@@ -1487,7 +1487,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0)
goto out;
- memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+ memcpy(orb->request.command_block, cmd->cmnd, cmd->cmd_len);
orb->base.callback = complete_command_orb;
orb->base.request_bus =
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 5a99e81d278..93f916720b1 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -30,6 +30,8 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pca9537", 4, },
{ "pca9538", 8, },
{ "pca9539", 16, },
+ { "pca9555", 16, },
+ { "pca9557", 8, },
/* REVISIT several pca955x parts should work here too */
{ }
};
@@ -193,7 +195,7 @@ static int __devinit pca953x_probe(struct i2c_client *client,
{
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
- int ret, i;
+ int ret;
pdata = client->dev.platform_data;
if (pdata == NULL)
diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c
index 9587869bdba..c1009d6f979 100644
--- a/drivers/hwmon/adt7473.c
+++ b/drivers/hwmon/adt7473.c
@@ -422,18 +422,14 @@ static ssize_t show_volt(struct device *dev, struct device_attribute *devattr,
* number in the range -128 to 127, or as an unsigned number that must
* be offset by 64.
*/
-static int decode_temp(struct adt7473_data *data, u8 raw)
+static int decode_temp(u8 twos_complement, u8 raw)
{
- if (data->temp_twos_complement)
- return (s8)raw;
- return raw - 64;
+ return twos_complement ? (s8)raw : raw - 64;
}
-static u8 encode_temp(struct adt7473_data *data, int cooked)
+static u8 encode_temp(u8 twos_complement, int cooked)
{
- if (data->temp_twos_complement)
- return (cooked & 0xFF);
- return cooked + 64;
+ return twos_complement ? cooked & 0xFF : cooked + 64;
}
static ssize_t show_temp_min(struct device *dev,
@@ -442,8 +438,9 @@ static ssize_t show_temp_min(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_min[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_min[attr->index]));
}
static ssize_t set_temp_min(struct device *dev,
@@ -455,7 +452,7 @@ static ssize_t set_temp_min(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_min[attr->index] = temp;
@@ -472,8 +469,9 @@ static ssize_t show_temp_max(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_max[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_max[attr->index]));
}
static ssize_t set_temp_max(struct device *dev,
@@ -485,7 +483,7 @@ static ssize_t set_temp_max(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_max[attr->index] = temp;
@@ -501,8 +499,9 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp[attr->index]));
}
static ssize_t show_fan_min(struct device *dev,
@@ -671,8 +670,9 @@ static ssize_t show_temp_tmax(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_tmax[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_tmax[attr->index]));
}
static ssize_t set_temp_tmax(struct device *dev,
@@ -684,7 +684,7 @@ static ssize_t set_temp_tmax(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_tmax[attr->index] = temp;
@@ -701,8 +701,9 @@ static ssize_t show_temp_tmin(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_tmin[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_tmin[attr->index]));
}
static ssize_t set_temp_tmin(struct device *dev,
@@ -714,7 +715,7 @@ static ssize_t set_temp_tmin(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_tmin[attr->index] = temp;
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 84712a22ace..fe2eea4d799 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -953,12 +953,8 @@ static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value)
static void asb100_init_client(struct i2c_client *client)
{
struct asb100_data *data = i2c_get_clientdata(client);
- int vid = 0;
- vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f;
- vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4;
data->vrm = vid_which_vrm();
- vid = vid_from_reg(vid, data->vrm);
/* Start monitoring */
asb100_write_value(client, ASB100_REG_CONFIG,
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 115f4090b98..fa769690515 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -248,7 +248,7 @@ static int lm75_detach_client(struct i2c_client *client)
/* All registers are word-sized, except for the configuration register.
LM75 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
+ the SMBus standard. */
static int lm75_read_value(struct i2c_client *client, u8 reg)
{
if (reg == LM75_REG_CONF)
@@ -257,9 +257,6 @@ static int lm75_read_value(struct i2c_client *client, u8 reg)
return swab16(i2c_smbus_read_word_data(client, reg));
}
-/* All registers are word-sized, except for the configuration register.
- LM75 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
{
if (reg == LM75_REG_CONF)
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index f61d8f4185b..eb03544c731 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -335,11 +335,23 @@ exit:
static int __init smsc47b397_find(unsigned short *addr)
{
u8 id, rev;
+ char *name;
superio_enter();
id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
- if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
+ switch(id) {
+ case 0x81:
+ name = "SCH5307-NS";
+ break;
+ case 0x6f:
+ name = "LPC47B397-NC";
+ break;
+ case 0x85:
+ case 0x8c:
+ name = "SCH5317";
+ break;
+ default:
superio_exit();
return -ENODEV;
}
@@ -352,8 +364,7 @@ static int __init smsc47b397_find(unsigned short *addr)
printk(KERN_INFO DRVNAME ": found SMSC %s "
"(base address 0x%04x, revision %u)\n",
- id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" :
- "LPC47B397-NC", *addr, rev);
+ name, *addr, rev);
superio_exit();
return 0;
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index ee35af93b57..ed3c019b78c 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -1024,10 +1024,9 @@ static struct sensor_device_attribute_2 w83793_vid[] = {
SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0),
SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1),
};
+static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm);
static struct sensor_device_attribute_2 sda_single_files[] = {
- SENSOR_ATTR_2(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm,
- NOT_USED, NOT_USED),
SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
store_chassis_clear, ALARM_STATUS, 30),
SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
@@ -1080,6 +1079,7 @@ static int w83793_detach_client(struct i2c_client *client)
for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
device_remove_file(dev, &w83793_vid[i].dev_attr);
+ device_remove_file(dev, &dev_attr_vrm);
for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
device_remove_file(dev, &w83793_left_fan[i].dev_attr);
@@ -1282,7 +1282,6 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
/* Initialize the chip */
w83793_init_client(client);
- data->vrm = vid_which_vrm();
/*
Only fan 1-5 has their own input pins,
Pwm 1-3 has their own pins
@@ -1293,7 +1292,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
val = w83793_read_value(client, W83793_REG_FANIN_CTRL);
/* check the function of pins 49-56 */
- if (!(tmp & 0x80)) {
+ if (tmp & 0x80) {
+ data->has_vid |= 0x2; /* has VIDB */
+ } else {
data->has_pwm |= 0x18; /* pwm 4,5 */
if (val & 0x01) { /* fan 6 */
data->has_fan |= 0x20;
@@ -1309,13 +1310,15 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
}
}
+ /* check the function of pins 37-40 */
+ if (!(tmp & 0x29))
+ data->has_vid |= 0x1; /* has VIDA */
if (0x08 == (tmp & 0x0c)) {
if (val & 0x08) /* fan 9 */
data->has_fan |= 0x100;
if (val & 0x10) /* fan 10 */
data->has_fan |= 0x200;
}
-
if (0x20 == (tmp & 0x30)) {
if (val & 0x20) /* fan 11 */
data->has_fan |= 0x400;
@@ -1359,13 +1362,6 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
if (tmp & 0x02)
data->has_temp |= 0x20;
- /* Detect the VID usage and ignore unused input */
- tmp = w83793_read_value(client, W83793_REG_MFC);
- if (!(tmp & 0x29))
- data->has_vid |= 0x1; /* has VIDA */
- if (tmp & 0x80)
- data->has_vid |= 0x2; /* has VIDB */
-
/* Register sysfs hooks */
for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) {
err = device_create_file(dev,
@@ -1381,6 +1377,12 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
if (err)
goto exit_remove;
}
+ if (data->has_vid) {
+ data->vrm = vid_which_vrm();
+ err = device_create_file(dev, &dev_attr_vrm);
+ if (err)
+ goto exit_remove;
+ }
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
err = device_create_file(dev, &sda_single_files[i].dev_attr);
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 77f2d482888..52e268e25da 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -301,8 +301,8 @@ static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
msleep(i);
}
- dev_err(&client->dev, "Couldn't read value from register 0x%02x. "
- "Please report.\n", reg);
+ dev_err(&client->dev, "Couldn't read value from register 0x%02x.\n",
+ reg);
return defval;
}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 099a0fe1745..591deda3f86 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1347,7 +1347,8 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
(d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
hwif->irq = port ? 15 : 14;
- hwif->host_flags = d->host_flags;
+ /* ->host_flags may be set by ->init_iops (or even earlier...) */
+ hwif->host_flags |= d->host_flags;
hwif->pio_mask = d->pio_mask;
/* ->set_pio_mode for DTC2278 is currently limited to port 0 */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 29d833e71cb..05710c7c122 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -520,8 +520,11 @@ static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
char *scratch = buf;
driver = container_of(drv, struct hpsb_protocol_driver, driver);
+ id = driver->id_table;
+ if (!id)
+ return 0;
- for (id = driver->id_table; id->match_flags != 0; id++) {
+ for (; id->match_flags != 0; id++) {
int need_coma = 0;
if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 877be9922c3..15906d005b0 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -405,7 +405,8 @@ hysdn_procconf_init(void)
sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
if ((card->procconf = (void *) proc_create(conf_name,
S_IFREG | S_IRUGO | S_IWUSR,
- hysdn_proc_entry)) != NULL) {
+ hysdn_proc_entry,
+ &conf_fops)) != NULL) {
hysdn_proclog_init(card); /* init the log file entry */
}
card = card->next; /* next entry */
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index 2bc9bf7e88e..8080249957a 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -85,27 +85,34 @@ static unsigned desc_size(const struct lguest_device_desc *desc)
+ desc->config_len;
}
-/* This tests (and acknowleges) a feature bit. */
-static bool lg_feature(struct virtio_device *vdev, unsigned fbit)
+/* This gets the device's feature bits. */
+static u32 lg_get_features(struct virtio_device *vdev)
{
+ unsigned int i;
+ u32 features = 0;
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
- u8 *features;
-
- /* Obviously if they ask for a feature off the end of our feature
- * bitmap, it's not set. */
- if (fbit / 8 > desc->feature_len)
- return false;
-
- /* The feature bitmap comes after the virtqueues. */
- features = lg_features(desc);
- if (!(features[fbit / 8] & (1 << (fbit % 8))))
- return false;
-
- /* We set the matching bit in the other half of the bitmap to tell the
- * Host we want to use this feature. We don't use this yet, but we
- * could in future. */
- features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
- return true;
+ u8 *in_features = lg_features(desc);
+
+ /* We do this the slow but generic way. */
+ for (i = 0; i < min(desc->feature_len * 8, 32); i++)
+ if (in_features[i / 8] & (1 << (i % 8)))
+ features |= (1 << i);
+
+ return features;
+}
+
+static void lg_set_features(struct virtio_device *vdev, u32 features)
+{
+ unsigned int i;
+ struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+ /* Second half of bitmap is features we accept. */
+ u8 *out_features = lg_features(desc) + desc->feature_len;
+
+ memset(out_features, 0, desc->feature_len);
+ for (i = 0; i < min(desc->feature_len * 8, 32); i++) {
+ if (features & (1 << i))
+ out_features[i / 8] |= (1 << (i % 8));
+ }
}
/* Once they've found a field, getting a copy of it is easy. */
@@ -137,20 +144,26 @@ static u8 lg_get_status(struct virtio_device *vdev)
return to_lgdev(vdev)->desc->status;
}
+/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the
+ * descriptor address of the device. A zero status means "reset". */
+static void set_status(struct virtio_device *vdev, u8 status)
+{
+ unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
+
+ /* We set the status. */
+ to_lgdev(vdev)->desc->status = status;
+ hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+}
+
static void lg_set_status(struct virtio_device *vdev, u8 status)
{
BUG_ON(!status);
- to_lgdev(vdev)->desc->status = status;
+ set_status(vdev, status);
}
-/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor
- * address of the device. The Host will zero the status and all the
- * features. */
static void lg_reset(struct virtio_device *vdev)
{
- unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
-
- hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+ set_status(vdev, 0);
}
/*
@@ -286,7 +299,8 @@ static void lg_del_vq(struct virtqueue *vq)
/* The ops structure which hooks everything together. */
static struct virtio_config_ops lguest_config_ops = {
- .feature = lg_feature,
+ .get_features = lg_get_features,
+ .set_features = lg_set_features,
.get = lg_get,
.set = lg_set,
.get_status = lg_get_status,
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 645e6e040bf..e73a000473c 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -102,7 +102,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
{
/* We have a limited number the number of CPUs in the lguest struct. */
- if (id >= NR_CPUS)
+ if (id >= ARRAY_SIZE(cpu->lg->cpus))
return -EINVAL;
/* Set up this CPU's id, and pointer back to the lguest struct. */
@@ -251,8 +251,6 @@ static ssize_t write(struct file *file, const char __user *in,
if (!lg || (cpu_id >= lg->nr_cpus))
return -EINVAL;
cpu = &lg->cpus[cpu_id];
- if (!cpu)
- return -EINVAL;
/* Once the Guest is dead, you can only read() why it died. */
if (lg->dead)
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index e812df607a5..fcd1aeccdf9 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -82,9 +82,8 @@ static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf);
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len);
+ size_t *retlen, void **virt, resource_size_t *phys);
+static void cfi_intelext_unpoint(struct mtd_info *mtd, 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);
@@ -1240,7 +1239,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
return ret;
}
-static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -1257,8 +1257,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
chipnum = (from >> cfi->chipshift);
ofs = from - (chipnum << cfi->chipshift);
- *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
+ *virt = map->virt + cfi->chips[chipnum].start + ofs;
*retlen = 0;
+ if (phys)
+ *phys = map->phys + cfi->chips[chipnum].start + ofs;
while (len) {
unsigned long thislen;
@@ -1291,7 +1293,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
return 0;
}
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index bf485ff4945..0399be17862 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -48,18 +48,21 @@ static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
}
static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = mtd->priv + from;
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
+ *virt = mtd->priv + from;
*retlen = len;
return 0;
}
-static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
- size_t len)
+static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
}
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 5f960182da9..c7987b1c5e0 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -57,20 +57,21 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
}
static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
- u_char *start = mtd->priv;
-
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = start + from;
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
+ *virt = mtd->priv + from;
*retlen = len;
return 0;
}
-static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len)
+static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
}
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index 7060a0895ce..bc998174906 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -134,7 +134,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
eoff_lo = end & (priv->asize - 1);
soff_lo = instr->addr & (priv->asize - 1);
- pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr);
+ pmc551_point(mtd, instr->addr, instr->len, &retlen,
+ (void **)&ptr, NULL);
if (soff_hi == eoff_hi || mtd->size == priv->asize) {
/* The whole thing fits within one access, so just one shot
@@ -154,7 +155,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
}
soff_hi += priv->asize;
pmc551_point(mtd, (priv->base_map0 | soff_hi),
- priv->asize, &retlen, &ptr);
+ priv->asize, &retlen,
+ (void **)&ptr, NULL);
}
memset(ptr, 0xff, eoff_lo);
}
@@ -170,7 +172,7 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
}
static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, u_char ** mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi;
@@ -188,6 +190,10 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
return -EINVAL;
}
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
soff_hi = from & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1);
@@ -198,13 +204,12 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
priv->curr_map0 = soff_hi;
}
- *mtdbuf = priv->start + soff_lo;
+ *virt = priv->start + soff_lo;
*retlen = len;
return 0;
}
-static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
- size_t len)
+static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_unpoint()\n");
@@ -242,7 +247,7 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
soff_lo = from & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
- pmc551_point(mtd, from, len, retlen, &ptr);
+ pmc551_point(mtd, from, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
@@ -263,7 +268,8 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
goto out;
}
soff_hi += priv->asize;
- pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+ pmc551_point(mtd, soff_hi, priv->asize, retlen,
+ (void **)&ptr, NULL);
}
memcpy(copyto, ptr, eoff_lo);
copyto += eoff_lo;
@@ -308,7 +314,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
soff_lo = to & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
- pmc551_point(mtd, to, len, retlen, &ptr);
+ pmc551_point(mtd, to, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
@@ -329,7 +335,8 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
goto out;
}
soff_hi += priv->asize;
- pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+ pmc551_point(mtd, soff_hi, priv->asize, retlen,
+ (void **)&ptr, NULL);
}
memcpy(ptr, copyfrom, eoff_lo);
copyfrom += eoff_lo;
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index d293add1857..cb86db746f2 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -76,8 +76,9 @@ static char *map;
static slram_mtd_list_t *slram_mtdlist = NULL;
static int slram_erase(struct mtd_info *, struct erase_info *);
-static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
-static void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
+static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
+ resource_size_t *);
+static void slram_unpoint(struct mtd_info *, loff_t, size_t);
static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -104,19 +105,23 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
}
static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
slram_priv_t *priv = mtd->priv;
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = priv->start + from;
+ *virt = priv->start + from;
*retlen = len;
return(0);
}
-static void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
}
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index 14ffb1a9302..c42f4b83f68 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -40,10 +40,12 @@ struct mtd_partition uclinux_romfs[] = {
/****************************************************************************/
int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct map_info *map = mtd->priv;
- *mtdbuf = (u_char *) (map->virt + ((int) from));
+ *virt = map->virt + from;
+ if (phys)
+ *phys = map->phys + from;
*retlen = len;
return(0);
}
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index c66902df317..07c70116934 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -68,7 +68,7 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
}
static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **buf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct mtd_part *part = PART(mtd);
if (from >= mtd->size)
@@ -76,14 +76,14 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
else if (from + len > mtd->size)
len = mtd->size - from;
return part->master->point (part->master, from + part->offset,
- len, retlen, buf);
+ len, retlen, virt, phys);
}
-static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
struct mtd_part *part = PART(mtd);
- part->master->unpoint (part->master, addr, from + part->offset, len);
+ part->master->unpoint(part->master, from + part->offset, len);
}
static int part_read_oob(struct mtd_info *mtd, loff_t from,
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index 414ceaecdb3..0adb287027a 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -94,6 +94,24 @@ struct at91_nand_host {
};
/*
+ * Enable NAND.
+ */
+static void at91_nand_enable(struct at91_nand_host *host)
+{
+ if (host->board->enable_pin)
+ at91_set_gpio_value(host->board->enable_pin, 0);
+}
+
+/*
+ * Disable NAND.
+ */
+static void at91_nand_disable(struct at91_nand_host *host)
+{
+ if (host->board->enable_pin)
+ at91_set_gpio_value(host->board->enable_pin, 1);
+}
+
+/*
* Hardware specific access to control-lines
*/
static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -101,11 +119,11 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
struct nand_chip *nand_chip = mtd->priv;
struct at91_nand_host *host = nand_chip->priv;
- if (host->board->enable_pin && (ctrl & NAND_CTRL_CHANGE)) {
+ if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_NCE)
- at91_set_gpio_value(host->board->enable_pin, 0);
+ at91_nand_enable(host);
else
- at91_set_gpio_value(host->board->enable_pin, 1);
+ at91_nand_disable(host);
}
if (cmd == NAND_CMD_NONE)
return;
@@ -128,24 +146,6 @@ static int at91_nand_device_ready(struct mtd_info *mtd)
}
/*
- * Enable NAND.
- */
-static void at91_nand_enable(struct at91_nand_host *host)
-{
- if (host->board->enable_pin)
- at91_set_gpio_value(host->board->enable_pin, 0);
-}
-
-/*
- * Disable NAND.
- */
-static void at91_nand_disable(struct at91_nand_host *host)
-{
- if (host->board->enable_pin)
- at91_set_gpio_value(host->board->enable_pin, 1);
-}
-
-/*
* write oob for small pages
*/
static int at91_nand_write_oob_512(struct mtd_info *mtd,
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index d7a3ea88edd..32a4f17d35f 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -67,6 +67,10 @@
#define FEC_MAX_PORTS 1
#endif
+#if defined(CONFIG_FADS) || defined(CONFIG_RPXCLASSIC) || defined(CONFIG_M5272)
+#define HAVE_mii_link_interrupt
+#endif
+
/*
* Define the fixed address of the FEC hardware.
*/
@@ -205,7 +209,10 @@ struct fec_enet_private {
cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
cbd_t *dirty_tx; /* The ring entries to be free()ed. */
uint tx_full;
- spinlock_t lock;
+ /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
+ spinlock_t hw_lock;
+ /* hold while accessing the mii_list_t() elements */
+ spinlock_t mii_lock;
uint phy_id;
uint phy_id_done;
@@ -309,6 +316,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
volatile fec_t *fecp;
volatile cbd_t *bdp;
unsigned short status;
+ unsigned long flags;
fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr;
@@ -318,6 +326,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 1;
}
+ spin_lock_irqsave(&fep->hw_lock, flags);
/* Fill in a Tx ring entry */
bdp = fep->cur_tx;
@@ -328,6 +337,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
* This should not happen, since dev->tbusy should be set.
*/
printk("%s: tx queue full!.\n", dev->name);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
return 1;
}
#endif
@@ -366,8 +376,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
flush_dcache_range((unsigned long)skb->data,
(unsigned long)skb->data + skb->len);
- spin_lock_irq(&fep->lock);
-
/* Send it on its way. Tell FEC it's ready, interrupt when done,
* it's the last BD of the frame, and to put the CRC on the end.
*/
@@ -396,7 +404,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
fep->cur_tx = (cbd_t *)bdp;
- spin_unlock_irq(&fep->lock);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
return 0;
}
@@ -454,19 +462,20 @@ fec_enet_interrupt(int irq, void * dev_id)
struct net_device *dev = dev_id;
volatile fec_t *fecp;
uint int_events;
- int handled = 0;
+ irqreturn_t ret = IRQ_NONE;
fecp = (volatile fec_t*)dev->base_addr;
/* Get the interrupt events that caused us to be here.
*/
- while ((int_events = fecp->fec_ievent) != 0) {
+ do {
+ int_events = fecp->fec_ievent;
fecp->fec_ievent = int_events;
/* Handle receive event in its own function.
*/
if (int_events & FEC_ENET_RXF) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_rx(dev);
}
@@ -475,17 +484,18 @@ fec_enet_interrupt(int irq, void * dev_id)
them as part of the transmit process.
*/
if (int_events & FEC_ENET_TXF) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_tx(dev);
}
if (int_events & FEC_ENET_MII) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_mii(dev);
}
- }
- return IRQ_RETVAL(handled);
+ } while (int_events);
+
+ return ret;
}
@@ -498,7 +508,7 @@ fec_enet_tx(struct net_device *dev)
struct sk_buff *skb;
fep = netdev_priv(dev);
- spin_lock(&fep->lock);
+ spin_lock_irq(&fep->hw_lock);
bdp = fep->dirty_tx;
while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
@@ -557,7 +567,7 @@ fec_enet_tx(struct net_device *dev)
}
}
fep->dirty_tx = (cbd_t *)bdp;
- spin_unlock(&fep->lock);
+ spin_unlock_irq(&fep->hw_lock);
}
@@ -584,6 +594,8 @@ fec_enet_rx(struct net_device *dev)
fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr;
+ spin_lock_irq(&fep->hw_lock);
+
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
*/
@@ -689,6 +701,8 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
*/
fecp->fec_r_des_active = 0;
#endif
+
+ spin_unlock_irq(&fep->hw_lock);
}
@@ -702,11 +716,11 @@ fec_enet_mii(struct net_device *dev)
uint mii_reg;
fep = netdev_priv(dev);
+ spin_lock_irq(&fep->mii_lock);
+
ep = fep->hwp;
mii_reg = ep->fec_mii_data;
- spin_lock(&fep->lock);
-
if ((mip = mii_head) == NULL) {
printk("MII and no head!\n");
goto unlock;
@@ -723,7 +737,7 @@ fec_enet_mii(struct net_device *dev)
ep->fec_mii_data = mip->mii_regval;
unlock:
- spin_unlock(&fep->lock);
+ spin_unlock_irq(&fep->mii_lock);
}
static int
@@ -737,12 +751,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
/* Add PHY address to register command.
*/
fep = netdev_priv(dev);
- regval |= fep->phy_addr << 23;
+ spin_lock_irqsave(&fep->mii_lock, flags);
+ regval |= fep->phy_addr << 23;
retval = 0;
- spin_lock_irqsave(&fep->lock,flags);
-
if ((mip = mii_free) != NULL) {
mii_free = mip->mii_next;
mip->mii_regval = regval;
@@ -759,9 +772,8 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
retval = 1;
}
- spin_unlock_irqrestore(&fep->lock,flags);
-
- return(retval);
+ spin_unlock_irqrestore(&fep->mii_lock, flags);
+ return retval;
}
static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
@@ -1222,7 +1234,7 @@ static phy_info_t const * const phy_info[] = {
};
/* ------------------------------------------------------------------------- */
-#if !defined(CONFIG_M532x)
+#ifdef HAVE_mii_link_interrupt
#ifdef CONFIG_RPXCLASSIC
static void
mii_link_interrupt(void *dev_id);
@@ -1362,18 +1374,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
unsigned short irq;
} *idp, id[] = {
{ "fec(TXF)", 23 },
- { "fec(TXB)", 24 },
- { "fec(TXFIFO)", 25 },
- { "fec(TXCR)", 26 },
{ "fec(RXF)", 27 },
- { "fec(RXB)", 28 },
{ "fec(MII)", 29 },
- { "fec(LC)", 30 },
- { "fec(HBERR)", 31 },
- { "fec(GRA)", 32 },
- { "fec(EBERR)", 33 },
- { "fec(BABT)", 34 },
- { "fec(BABR)", 35 },
{ NULL },
};
@@ -1533,18 +1535,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
unsigned short irq;
} *idp, id[] = {
{ "fec(TXF)", 23 },
- { "fec(TXB)", 24 },
- { "fec(TXFIFO)", 25 },
- { "fec(TXCR)", 26 },
{ "fec(RXF)", 27 },
- { "fec(RXB)", 28 },
{ "fec(MII)", 29 },
- { "fec(LC)", 30 },
- { "fec(HBERR)", 31 },
- { "fec(GRA)", 32 },
- { "fec(EBERR)", 33 },
- { "fec(BABT)", 34 },
- { "fec(BABR)", 35 },
{ NULL },
};
@@ -1660,18 +1652,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
unsigned short irq;
} *idp, id[] = {
{ "fec(TXF)", 36 },
- { "fec(TXB)", 37 },
- { "fec(TXFIFO)", 38 },
- { "fec(TXCR)", 39 },
{ "fec(RXF)", 40 },
- { "fec(RXB)", 41 },
{ "fec(MII)", 42 },
- { "fec(LC)", 43 },
- { "fec(HBERR)", 44 },
- { "fec(GRA)", 45 },
- { "fec(EBERR)", 46 },
- { "fec(BABT)", 47 },
- { "fec(BABR)", 48 },
{ NULL },
};
@@ -2126,6 +2108,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
/* This interrupt occurs when the PHY detects a link change.
*/
+#ifdef HAVE_mii_link_interrupt
#ifdef CONFIG_RPXCLASSIC
static void
mii_link_interrupt(void *dev_id)
@@ -2148,6 +2131,7 @@ mii_link_interrupt(int irq, void * dev_id)
return IRQ_HANDLED;
}
+#endif
static int
fec_enet_open(struct net_device *dev)
@@ -2243,13 +2227,13 @@ static void set_multicast_list(struct net_device *dev)
/* Catch all multicast addresses, so set the
* filter to all 1's.
*/
- ep->fec_hash_table_high = 0xffffffff;
- ep->fec_hash_table_low = 0xffffffff;
+ ep->fec_grp_hash_table_high = 0xffffffff;
+ ep->fec_grp_hash_table_low = 0xffffffff;
} else {
/* Clear filter and add the addresses in hash register.
*/
- ep->fec_hash_table_high = 0;
- ep->fec_hash_table_low = 0;
+ ep->fec_grp_hash_table_high = 0;
+ ep->fec_grp_hash_table_low = 0;
dmi = dev->mc_list;
@@ -2280,9 +2264,9 @@ static void set_multicast_list(struct net_device *dev)
hash = (crc >> (32 - HASH_BITS)) & 0x3f;
if (hash > 31)
- ep->fec_hash_table_high |= 1 << (hash - 32);
+ ep->fec_grp_hash_table_high |= 1 << (hash - 32);
else
- ep->fec_hash_table_low |= 1 << hash;
+ ep->fec_grp_hash_table_low |= 1 << hash;
}
}
}
@@ -2332,6 +2316,9 @@ int __init fec_enet_init(struct net_device *dev)
return -ENOMEM;
}
+ spin_lock_init(&fep->hw_lock);
+ spin_lock_init(&fep->mii_lock);
+
/* Create an Ethernet device instance.
*/
fecp = (volatile fec_t *) fec_hw[index];
@@ -2430,11 +2417,15 @@ int __init fec_enet_init(struct net_device *dev)
*/
fec_request_intrs(dev);
- fecp->fec_hash_table_high = 0;
- fecp->fec_hash_table_low = 0;
+ fecp->fec_grp_hash_table_high = 0;
+ fecp->fec_grp_hash_table_low = 0;
fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
fecp->fec_ecntrl = 2;
fecp->fec_r_des_active = 0;
+#ifndef CONFIG_M5272
+ fecp->fec_hash_table_high = 0;
+ fecp->fec_hash_table_low = 0;
+#endif
dev->base_addr = (unsigned long)fecp;
@@ -2455,8 +2446,7 @@ int __init fec_enet_init(struct net_device *dev)
/* Clear and enable interrupts */
fecp->fec_ievent = 0xffc00000;
- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
/* Queue up command to detect the PHY and initialize the
* remainder of the interface.
@@ -2500,8 +2490,8 @@ fec_restart(struct net_device *dev, int duplex)
/* Reset all multicast.
*/
- fecp->fec_hash_table_high = 0;
- fecp->fec_hash_table_low = 0;
+ fecp->fec_grp_hash_table_high = 0;
+ fecp->fec_grp_hash_table_low = 0;
/* Set maximum receive buffer size.
*/
@@ -2583,8 +2573,7 @@ fec_restart(struct net_device *dev, int duplex)
/* Enable interrupts we wish to service.
*/
- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
}
static void
@@ -2624,7 +2613,7 @@ fec_stop(struct net_device *dev)
static int __init fec_enet_module_init(void)
{
struct net_device *dev;
- int i, j, err;
+ int i, err;
DECLARE_MAC_BUF(mac);
printk("FEC ENET Version 0.2\n");
diff --git a/drivers/net/fec.h b/drivers/net/fec.h
index 1d421606984..292719dacef 100644
--- a/drivers/net/fec.h
+++ b/drivers/net/fec.h
@@ -88,8 +88,8 @@ typedef struct fec {
unsigned long fec_reserved7[158];
unsigned long fec_addr_low; /* Low 32bits MAC address */
unsigned long fec_addr_high; /* High 16bits MAC address */
- unsigned long fec_hash_table_high; /* High 32bits hash table */
- unsigned long fec_hash_table_low; /* Low 32bits hash table */
+ unsigned long fec_grp_hash_table_high;/* High 32bits hash table */
+ unsigned long fec_grp_hash_table_low; /* Low 32bits hash table */
unsigned long fec_r_des_start; /* Receive descriptor ring */
unsigned long fec_x_des_start; /* Transmit descriptor ring */
unsigned long fec_r_buff_size; /* Maximum receive buff size */
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index d21b7ab64bd..5f9c42e7a7f 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -43,6 +43,29 @@
#define DRIVER_NAME "mpc52xx-fec"
+#define FEC5200_PHYADDR_NONE (-1)
+#define FEC5200_PHYADDR_7WIRE (-2)
+
+/* Private driver data structure */
+struct mpc52xx_fec_priv {
+ int duplex;
+ int speed;
+ int r_irq;
+ int t_irq;
+ struct mpc52xx_fec __iomem *fec;
+ struct bcom_task *rx_dmatsk;
+ struct bcom_task *tx_dmatsk;
+ spinlock_t lock;
+ int msg_enable;
+
+ /* MDIO link details */
+ int phy_addr;
+ unsigned int phy_speed;
+ struct phy_device *phydev;
+ enum phy_state link;
+};
+
+
static irqreturn_t mpc52xx_fec_interrupt(int, void *);
static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *);
static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *);
@@ -223,7 +246,7 @@ static int mpc52xx_fec_phy_start(struct net_device *dev)
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
int err;
- if (!priv->has_phy)
+ if (priv->phy_addr < 0)
return 0;
err = mpc52xx_fec_init_phy(dev);
@@ -243,7 +266,7 @@ static void mpc52xx_fec_phy_stop(struct net_device *dev)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
- if (!priv->has_phy)
+ if (!priv->phydev)
return;
phy_disconnect(priv->phydev);
@@ -255,7 +278,7 @@ static void mpc52xx_fec_phy_stop(struct net_device *dev)
static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
struct mii_ioctl_data *mii_data, int cmd)
{
- if (!priv->has_phy)
+ if (!priv->phydev)
return -ENOTSUPP;
return phy_mii_ioctl(priv->phydev, mii_data, cmd);
@@ -265,7 +288,7 @@ static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
{
struct mpc52xx_fec __iomem *fec = priv->fec;
- if (!priv->has_phy)
+ if (priv->phydev)
return;
out_be32(&fec->mii_speed, priv->phy_speed);
@@ -704,7 +727,7 @@ static void mpc52xx_fec_start(struct net_device *dev)
rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
rcntrl |= FEC_RCNTRL_FCE;
- if (priv->has_phy)
+ if (priv->phy_addr != FEC5200_PHYADDR_7WIRE)
rcntrl |= FEC_RCNTRL_MII_MODE;
if (priv->duplex == DUPLEX_FULL)
@@ -864,7 +887,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
struct net_device *ndev;
struct mpc52xx_fec_priv *priv = NULL;
struct resource mem;
- const phandle *ph;
+ struct device_node *phy_node;
+ const phandle *phy_handle;
+ const u32 *prop;
+ int prop_size;
phys_addr_t rx_fifo;
phys_addr_t tx_fifo;
@@ -948,26 +974,37 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT);
- priv->duplex = DUPLEX_FULL;
-
- /* is the phy present in device tree? */
- ph = of_get_property(op->node, "phy-handle", NULL);
- if (ph) {
- const unsigned int *prop;
- struct device_node *phy_dn;
- priv->has_phy = 1;
- phy_dn = of_find_node_by_phandle(*ph);
- prop = of_get_property(phy_dn, "reg", NULL);
- priv->phy_addr = *prop;
+ /*
+ * Link mode configuration
+ */
- of_node_put(phy_dn);
+ /* Start with safe defaults for link connection */
+ priv->phy_addr = FEC5200_PHYADDR_NONE;
+ priv->speed = 100;
+ priv->duplex = DUPLEX_HALF;
+ priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
+
+ /* the 7-wire property means don't use MII mode */
+ if (of_find_property(op->node, "fsl,7-wire-mode", NULL))
+ priv->phy_addr = FEC5200_PHYADDR_7WIRE;
+
+ /* The current speed preconfigures the speed of the MII link */
+ prop = of_get_property(op->node, "current-speed", &prop_size);
+ if (prop && (prop_size >= sizeof(u32) * 2)) {
+ priv->speed = prop[0];
+ priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;
+ }
- /* Phy speed */
- priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
- } else {
- dev_info(&ndev->dev, "can't find \"phy-handle\" in device"
- " tree, using 7-wire mode\n");
+ /* If there is a phy handle, setup link to that phy */
+ phy_handle = of_get_property(op->node, "phy-handle", &prop_size);
+ if (phy_handle && (prop_size >= sizeof(phandle))) {
+ phy_node = of_find_node_by_phandle(*phy_handle);
+ prop = of_get_property(phy_node, "reg", &prop_size);
+ if (prop && (prop_size >= sizeof(u32)))
+ if ((*prop >= 0) && (*prop < PHY_MAX_ADDR))
+ priv->phy_addr = *prop;
+ of_node_put(phy_node);
}
/* Hardware init */
@@ -982,6 +1019,20 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
if (rv < 0)
goto probe_error;
+ /* Now report the link setup */
+ switch (priv->phy_addr) {
+ case FEC5200_PHYADDR_NONE:
+ dev_info(&ndev->dev, "Fixed speed MII link: %i%cD\n",
+ priv->speed, priv->duplex ? 'F' : 'H');
+ break;
+ case FEC5200_PHYADDR_7WIRE:
+ dev_info(&ndev->dev, "using 7-wire PHY mode\n");
+ break;
+ default:
+ dev_info(&ndev->dev, "Using PHY at MDIO address %i\n",
+ priv->phy_addr);
+ }
+
/* We're done ! */
dev_set_drvdata(&op->dev, ndev);
diff --git a/drivers/net/fec_mpc52xx.h b/drivers/net/fec_mpc52xx.h
index 8b1f75397b9..a227a525bdb 100644
--- a/drivers/net/fec_mpc52xx.h
+++ b/drivers/net/fec_mpc52xx.h
@@ -26,25 +26,6 @@
#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000)
-struct mpc52xx_fec_priv {
- int duplex;
- int r_irq;
- int t_irq;
- struct mpc52xx_fec __iomem *fec;
- struct bcom_task *rx_dmatsk;
- struct bcom_task *tx_dmatsk;
- spinlock_t lock;
- int msg_enable;
-
- int has_phy;
- unsigned int phy_speed;
- unsigned int phy_addr;
- struct phy_device *phydev;
- enum phy_state link;
- int speed;
-};
-
-
/* ======================================================================== */
/* Hardware register sets & bits */
/* ======================================================================== */
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 555b70c8b86..f926b5ab3d0 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -41,6 +41,9 @@ struct virtnet_info
struct net_device *dev;
struct napi_struct napi;
+ /* The skb we couldn't send because buffers were full. */
+ struct sk_buff *last_xmit_skb;
+
/* Number of input buffers, and max we've ever had. */
unsigned int num, max;
@@ -142,10 +145,10 @@ drop:
static void try_fill_recv(struct virtnet_info *vi)
{
struct sk_buff *skb;
- struct scatterlist sg[1+MAX_SKB_FRAGS];
+ struct scatterlist sg[2+MAX_SKB_FRAGS];
int num, err;
- sg_init_table(sg, 1+MAX_SKB_FRAGS);
+ sg_init_table(sg, 2+MAX_SKB_FRAGS);
for (;;) {
skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN);
if (unlikely(!skb))
@@ -221,23 +224,22 @@ static void free_old_xmit_skbs(struct virtnet_info *vi)
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_bytes += skb->len;
vi->dev->stats.tx_packets++;
kfree_skb(skb);
}
}
-static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
{
- struct virtnet_info *vi = netdev_priv(dev);
- int num, err;
- struct scatterlist sg[1+MAX_SKB_FRAGS];
+ int num;
+ struct scatterlist sg[2+MAX_SKB_FRAGS];
struct virtio_net_hdr *hdr;
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
- sg_init_table(sg, 1+MAX_SKB_FRAGS);
+ sg_init_table(sg, 2+MAX_SKB_FRAGS);
- pr_debug("%s: xmit %p " MAC_FMT "\n", dev->name, skb,
+ pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb,
dest[0], dest[1], dest[2],
dest[3], dest[4], dest[5]);
@@ -272,30 +274,51 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
vnet_hdr_to_sg(sg, skb);
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
- __skb_queue_head(&vi->send, skb);
+
+ return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+}
+
+static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
again:
/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs(vi);
- 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);
- netif_stop_queue(dev);
-
- /* Activate callback for using skbs: if this returns false it
- * means some were used in the meantime. */
- if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
- vi->svq->vq_ops->disable_cb(vi->svq);
- netif_start_queue(dev);
- goto again;
+
+ /* If we has a buffer left over from last time, send it now. */
+ if (vi->last_xmit_skb) {
+ if (xmit_skb(vi, vi->last_xmit_skb) != 0) {
+ /* Drop this skb: we only queue one. */
+ vi->dev->stats.tx_dropped++;
+ kfree_skb(skb);
+ goto stop_queue;
}
- __skb_unlink(skb, &vi->send);
+ vi->last_xmit_skb = NULL;
+ }
- return NETDEV_TX_BUSY;
+ /* Put new one in send queue and do transmit */
+ __skb_queue_head(&vi->send, skb);
+ if (xmit_skb(vi, skb) != 0) {
+ vi->last_xmit_skb = skb;
+ goto stop_queue;
}
+done:
vi->svq->vq_ops->kick(vi->svq);
-
- return 0;
+ return NETDEV_TX_OK;
+
+stop_queue:
+ pr_debug("%s: virtio not prepared to send\n", dev->name);
+ netif_stop_queue(dev);
+
+ /* Activate callback for using skbs: if this returns false it
+ * means some were used in the meantime. */
+ if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+ vi->svq->vq_ops->disable_cb(vi->svq);
+ netif_start_queue(dev);
+ goto again;
+ }
+ goto done;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -355,17 +378,26 @@ static int virtnet_probe(struct virtio_device *vdev)
SET_NETDEV_DEV(dev, &vdev->dev);
/* Do we support "hardware" checksums? */
- if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) {
+ if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
/* This opens up the world of extra features. */
dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
- if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) {
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
dev->features |= NETIF_F_TSO | NETIF_F_UFO
| NETIF_F_TSO_ECN | NETIF_F_TSO6;
}
+ /* Individual feature bits: what can host handle? */
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4))
+ dev->features |= NETIF_F_TSO;
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6))
+ dev->features |= NETIF_F_TSO6;
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
+ dev->features |= NETIF_F_TSO_ECN;
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
+ dev->features |= NETIF_F_UFO;
}
/* Configuration may specify what MAC to use. Otherwise random. */
- if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) {
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
vdev->config->get(vdev,
offsetof(struct virtio_net_config, mac),
dev->dev_addr, dev->addr_len);
@@ -454,7 +486,15 @@ static struct virtio_device_id id_table[] = {
{ 0 },
};
+static unsigned int features[] = {
+ VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
+ VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
+ VIRTIO_NET_F_HOST_ECN,
+};
+
static struct virtio_driver virtio_net = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c
index 74e051535d6..c78d77fd7e3 100644
--- a/drivers/pcmcia/au1000_db1x00.c
+++ b/drivers/pcmcia/au1000_db1x00.c
@@ -194,7 +194,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
default:
pwr |= SET_VCC_VPP(0,0,sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
state->Vcc,
state->Vpp);
break;
@@ -215,7 +215,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
default:
pwr |= SET_VCC_VPP(0,0,sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
state->Vcc,
state->Vpp);
break;
@@ -224,7 +224,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
default: /* what's this ? */
pwr |= SET_VCC_VPP(0,0,sock);
printk(KERN_ERR "%s: bad Vcc %d\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
break;
}
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index b693367d38c..75e8f8505e4 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -41,6 +41,7 @@
#include <linux/notifier.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <asm/io.h>
@@ -71,7 +72,7 @@ extern struct au1000_pcmcia_socket au1000_pcmcia_socket[];
u32 *pcmcia_base_vaddrs[2];
extern const unsigned long mips_io_port_base;
-DECLARE_MUTEX(pcmcia_sockets_lock);
+static DEFINE_MUTEX(pcmcia_sockets_lock);
static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = {
au1x_board_init,
@@ -472,7 +473,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev)
struct skt_dev_info *sinfo = dev_get_drvdata(dev);
int i;
- down(&pcmcia_sockets_lock);
+ mutex_lock(&pcmcia_sockets_lock);
dev_set_drvdata(dev, NULL);
for (i = 0; i < sinfo->nskt; i++) {
@@ -488,7 +489,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev)
}
kfree(sinfo);
- up(&pcmcia_sockets_lock);
+ mutex_unlock(&pcmcia_sockets_lock);
return 0;
}
@@ -501,13 +502,13 @@ static int au1x00_drv_pcmcia_probe(struct device *dev)
{
int i, ret = -ENODEV;
- down(&pcmcia_sockets_lock);
+ mutex_lock(&pcmcia_sockets_lock);
for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) {
ret = au1x00_pcmcia_hw_init[i](dev);
if (ret == 0)
break;
}
- up(&pcmcia_sockets_lock);
+ mutex_unlock(&pcmcia_sockets_lock);
return ret;
}
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index 86c0808d6a0..157e41423a0 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -244,7 +244,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -272,7 +272,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -300,7 +300,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -309,7 +309,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
default: /* what's this ? */
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock);
printk(KERN_ERR "%s: bad Vcc %d\n",
- __FUNCTION__, configure->vcc);
+ __func__, configure->vcc);
break;
}
@@ -353,7 +353,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
default:
pcr |= SET_VCC_VPP(0,0);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -374,7 +374,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
default:
pcr |= SET_VCC_VPP(0,0);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -383,7 +383,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
default: /* what's this ? */
pcr |= SET_VCC_VPP(0,0);
printk(KERN_ERR "%s: bad Vcc %d\n",
- __FUNCTION__, configure->vcc);
+ __func__, configure->vcc);
break;
}
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index ce9d5c44a7b..c78ed534751 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -56,7 +56,7 @@
#define PCMCIA_IRQ AU1000_GPIO_4
#if 0
-#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args)
+#define DEBUG(x, args...) printk(__func__ ": " x, ##args)
#else
#define DEBUG(x,args...)
#endif
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 714baaeb6da..fb2f38dc92c 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -209,7 +209,7 @@ static void cardbus_assign_irqs(struct pci_bus *bus, int irq)
}
}
-int cb_alloc(struct pcmcia_socket * s)
+int __ref cb_alloc(struct pcmcia_socket * s)
{
struct pci_bus *bus = s->cb_dev->subordinate;
struct pci_dev *dev;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 5a85871f5ee..e40775443d0 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1520,7 +1520,7 @@ static void pcmcia_bus_remove_socket(struct device *dev,
/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
-static struct class_interface pcmcia_bus_interface = {
+static struct class_interface pcmcia_bus_interface __refdata = {
.class = &pcmcia_socket_class,
.add_dev = &pcmcia_bus_add_socket,
.remove_dev = &pcmcia_bus_remove_socket,
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index e54ecc580d9..e13618656ff 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -53,7 +53,7 @@ static int i82092aa_socket_resume (struct pci_dev *dev)
}
#endif
-static struct pci_driver i82092aa_pci_drv = {
+static struct pci_driver i82092aa_pci_driver = {
.name = "i82092aa",
.id_table = i82092aa_pci_ids,
.probe = i82092aa_pci_probe,
@@ -714,13 +714,13 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_
static int i82092aa_module_init(void)
{
- return pci_register_driver(&i82092aa_pci_drv);
+ return pci_register_driver(&i82092aa_pci_driver);
}
static void i82092aa_module_exit(void)
{
enter("i82092aa_module_exit");
- pci_unregister_driver(&i82092aa_pci_drv);
+ pci_unregister_driver(&i82092aa_pci_driver);
if (sockets[0].io_base>0)
release_region(sockets[0].io_base, 2);
leave("i82092aa_module_exit");
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index bb6db3a582b..46314b42076 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -153,7 +153,7 @@ omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
static int omap_cf_ss_suspend(struct pcmcia_socket *s)
{
- pr_debug("%s: %s\n", driver_name, __FUNCTION__);
+ pr_debug("%s: %s\n", driver_name, __func__);
return omap_cf_set_socket(s, &dead_socket);
}
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index abc10fe49bd..8bed1dab903 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -778,7 +778,7 @@ static struct pci_device_id pd6729_pci_ids[] = {
};
MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
-static struct pci_driver pd6729_pci_drv = {
+static struct pci_driver pd6729_pci_driver = {
.name = "pd6729",
.id_table = pd6729_pci_ids,
.probe = pd6729_pci_probe,
@@ -791,12 +791,12 @@ static struct pci_driver pd6729_pci_drv = {
static int pd6729_module_init(void)
{
- return pci_register_driver(&pd6729_pci_drv);
+ return pci_register_driver(&pd6729_pci_driver);
}
static void pd6729_module_exit(void)
{
- pci_unregister_driver(&pd6729_pci_drv);
+ pci_unregister_driver(&pd6729_pci_driver);
}
module_init(pd6729_module_init);
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c
index 4a05802213c..881ec8a8e38 100644
--- a/drivers/pcmcia/pxa2xx_lubbock.c
+++ b/drivers/pcmcia/pxa2xx_lubbock.c
@@ -87,7 +87,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
ret = -1;
}
@@ -104,7 +104,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
pa_dwr_set |= GPIO_A0;
else {
printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
ret = -1;
break;
}
@@ -128,14 +128,14 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
ret = -1;
break;
}
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
ret = -1;
break;
}
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 6fa5eaaab8a..145b85e0f02 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -99,7 +99,7 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
case 50: power |= MST_PCMCIA_PWR_VCC_50; break;
default:
printk(KERN_ERR "%s(): bad Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
ret = -1;
}
@@ -111,7 +111,7 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
power |= MST_PCMCIA_PWR_VPP_VCC;
} else {
printk(KERN_ERR "%s(): bad Vpp %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
ret = -1;
}
}
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index a8d10070772..0fcf763b917 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -1045,7 +1045,7 @@ static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
device_remove_file(dev, *attr);
}
-static struct class_interface pccard_rsrc_interface = {
+static struct class_interface pccard_rsrc_interface __refdata = {
.class = &pcmcia_socket_class,
.add_dev = &pccard_sysfs_add_rsrc,
.remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c
index 7c57fdd3c8d..ce133ce81c1 100644
--- a/drivers/pcmcia/sa1100_assabet.c
+++ b/drivers/pcmcia/sa1100_assabet.c
@@ -66,14 +66,14 @@ assabet_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_stat
case 50:
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
- __FUNCTION__);
+ __func__);
case 33: /* Can only apply 3.3V to the CF slot. */
mask = ASSABET_BCR_CF_PWR;
break;
default:
- printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __func__,
state->Vcc);
return -1;
}
diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c
index 62bfc7566ec..607c3f326ec 100644
--- a/drivers/pcmcia/sa1100_badge4.c
+++ b/drivers/pcmcia/sa1100_badge4.c
@@ -82,14 +82,14 @@ badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state
case 0:
if ((state->Vcc != 0) &&
(state->Vcc != badge4_pcmvcc)) {
- complain_about_jumpering(__FUNCTION__, "pcmvcc",
+ complain_about_jumpering(__func__, "pcmvcc",
badge4_pcmvcc, state->Vcc);
// Apply power regardless of the jumpering.
// return -1;
}
if ((state->Vpp != 0) &&
(state->Vpp != badge4_pcmvpp)) {
- complain_about_jumpering(__FUNCTION__, "pcmvpp",
+ complain_about_jumpering(__func__, "pcmvpp",
badge4_pcmvpp, state->Vpp);
return -1;
}
@@ -98,7 +98,7 @@ badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state
case 1:
if ((state->Vcc != 0) &&
(state->Vcc != badge4_cfvcc)) {
- complain_about_jumpering(__FUNCTION__, "cfvcc",
+ complain_about_jumpering(__func__, "cfvcc",
badge4_cfvcc, state->Vcc);
return -1;
}
@@ -143,7 +143,7 @@ int pcmcia_badge4_init(struct device *dev)
if (machine_is_badge4()) {
printk(KERN_INFO
"%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
- __FUNCTION__,
+ __func__,
badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2);
diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c
index 549a1529fe3..7c3951a2675 100644
--- a/drivers/pcmcia/sa1100_cerf.c
+++ b/drivers/pcmcia/sa1100_cerf.c
@@ -63,7 +63,7 @@ cerf_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
return -1;
}
diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c
index 6284c35dabc..2167e6714d2 100644
--- a/drivers/pcmcia/sa1100_jornada720.c
+++ b/drivers/pcmcia/sa1100_jornada720.c
@@ -42,7 +42,7 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
unsigned int pa_dwr_mask, pa_dwr_set;
int ret;
-printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
+printk("%s(): config socket %d vcc %d vpp %d\n", __func__,
skt->nr, state->Vcc, state->Vpp);
switch (skt->nr) {
@@ -74,7 +74,7 @@ printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
return -1;
}
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
index 5bc9e9532b9..687492fcd5b 100644
--- a/drivers/pcmcia/sa1100_neponset.c
+++ b/drivers/pcmcia/sa1100_neponset.c
@@ -59,7 +59,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta
ncr_set = NCR_A0VPP;
else {
printk(KERN_ERR "%s(): unrecognized VPP %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
return -1;
}
break;
@@ -71,7 +71,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
return -1;
}
break;
diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c
index 9456f5478d0..494912fccc0 100644
--- a/drivers/pcmcia/sa1100_shannon.c
+++ b/drivers/pcmcia/sa1100_shannon.c
@@ -73,19 +73,19 @@ shannon_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
{
switch (state->Vcc) {
case 0: /* power off */
- printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __func__);
break;
case 50:
- printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __func__);
case 33:
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
return -1;
}
- printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __func__);
/* Silently ignore Vpp, output enable, speaker enable. */
diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c
index 04d6f7f75f7..42567de894b 100644
--- a/drivers/pcmcia/sa1100_simpad.c
+++ b/drivers/pcmcia/sa1100_simpad.c
@@ -90,7 +90,7 @@ simpad_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
local_irq_restore(flags);
return -1;
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index aa7779d8975..420a77540f4 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -37,6 +37,7 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
+#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
@@ -353,7 +354,7 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m
(map->flags&MAP_PREFETCH)?"PREFETCH ":"");
if (map->map >= MAX_IO_WIN) {
- printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
+ printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
map->map);
return -1;
}
@@ -578,7 +579,7 @@ EXPORT_SYMBOL(soc_pcmcia_enable_irqs);
LIST_HEAD(soc_pcmcia_sockets);
-DECLARE_MUTEX(soc_pcmcia_sockets_lock);
+static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
static const char *skt_names[] = {
"PCMCIA socket 0",
@@ -601,11 +602,11 @@ soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data)
struct cpufreq_freqs *freqs = data;
int ret = 0;
- down(&soc_pcmcia_sockets_lock);
+ mutex_lock(&soc_pcmcia_sockets_lock);
list_for_each_entry(skt, &soc_pcmcia_sockets, node)
if ( skt->ops->frequency_change )
ret += skt->ops->frequency_change(skt, val, freqs);
- up(&soc_pcmcia_sockets_lock);
+ mutex_unlock(&soc_pcmcia_sockets_lock);
return ret;
}
@@ -642,7 +643,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
struct soc_pcmcia_socket *skt;
int ret, i;
- down(&soc_pcmcia_sockets_lock);
+ mutex_lock(&soc_pcmcia_sockets_lock);
sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
if (!sinfo) {
@@ -782,7 +783,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
kfree(sinfo);
out:
- up(&soc_pcmcia_sockets_lock);
+ mutex_unlock(&soc_pcmcia_sockets_lock);
return ret;
}
@@ -793,7 +794,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev)
dev_set_drvdata(dev, NULL);
- down(&soc_pcmcia_sockets_lock);
+ mutex_lock(&soc_pcmcia_sockets_lock);
for (i = 0; i < sinfo->nskt; i++) {
struct soc_pcmcia_socket *skt = &sinfo->skt[i];
@@ -818,7 +819,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev)
if (list_empty(&soc_pcmcia_sockets))
soc_pcmcia_cpufreq_unregister();
- up(&soc_pcmcia_sockets_lock);
+ mutex_unlock(&soc_pcmcia_sockets_lock);
kfree(sinfo);
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 6f14126889b..1edc1da9d35 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -133,7 +133,6 @@ extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_
extern struct list_head soc_pcmcia_sockets;
-extern struct semaphore soc_pcmcia_sockets_lock;
extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr);
extern int soc_common_drv_pcmcia_remove(struct device *dev);
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index 2e2c457a0fe..5ff9a4c0447 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -591,7 +591,8 @@ static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p,
p[1] = map & 0xff;
p[2] = (map >> 8) & 0xff;
- dev_dbg(&dev->dev, " encode irq %d\n", res->start);
+ dev_dbg(&dev->dev, " encode irq %llu\n",
+ (unsigned long long)res->start);
}
static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
@@ -602,7 +603,8 @@ static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
map = 1 << res->start;
p[1] = map & 0xff;
- dev_dbg(&dev->dev, " encode dma %d\n", res->start);
+ dev_dbg(&dev->dev, " encode dma %llu\n",
+ (unsigned long long)res->start);
}
static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c
index 6c9592ce499..85edf945ab8 100644
--- a/drivers/ps3/ps3-lpm.c
+++ b/drivers/ps3/ps3-lpm.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
+#include <asm/time.h>
#include <asm/ps3.h>
#include <asm/lv1call.h>
#include <asm/cell-pmu.h>
diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c
index 7605453b74f..f17513dd9d4 100644
--- a/drivers/ps3/ps3-sys-manager.c
+++ b/drivers/ps3/ps3-sys-manager.c
@@ -184,10 +184,7 @@ enum ps3_sys_manager_next_op {
/**
* enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask).
- * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button, IR
- * controller, and bluetooth controller.
- * @PS3_SM_WAKE_RTC:
- * @PS3_SM_WAKE_RTC_ERROR:
+ * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button.
* @PS3_SM_WAKE_W_O_L: Ether or wireless LAN.
* @PS3_SM_WAKE_P_O_R: Power on reset.
*
@@ -200,8 +197,6 @@ enum ps3_sys_manager_next_op {
enum ps3_sys_manager_wake_source {
/* version 3 */
PS3_SM_WAKE_DEFAULT = 0,
- PS3_SM_WAKE_RTC = 0x00000040,
- PS3_SM_WAKE_RTC_ERROR = 0x00000080,
PS3_SM_WAKE_W_O_L = 0x00000400,
PS3_SM_WAKE_P_O_R = 0x80000000,
};
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 37b85c67b11..c8bad675dbd 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -1055,7 +1055,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level,
rec->scsi_result = scsi_cmnd->result;
rec->scsi_cmnd = (unsigned long)scsi_cmnd;
rec->scsi_serial = scsi_cmnd->serial_number;
- memcpy(rec->scsi_opcode, &scsi_cmnd->cmnd,
+ memcpy(rec->scsi_opcode, scsi_cmnd->cmnd,
min((int)scsi_cmnd->cmd_len,
ZFCP_DBF_SCSI_OPCODE));
rec->scsi_retries = scsi_cmnd->retries;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 9af2330f07a..b2ea4ea051f 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -4014,7 +4014,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n",
scpnt->result);
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
- (void *) &scpnt->cmnd, scpnt->cmd_len);
+ scpnt->cmnd, scpnt->cmd_len);
ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n",
fcp_rsp_iu->fcp_sns_len);
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index f4c4fe90240..f5a9addb705 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -599,7 +599,7 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
(struct NCR_700_command_slot *)SCp->host_scribble;
dma_unmap_single(hostdata->dev, slot->pCmd,
- sizeof(SCp->cmnd), DMA_TO_DEVICE);
+ MAX_COMMAND_SIZE, DMA_TO_DEVICE);
if (slot->flags == NCR_700_FLAG_AUTOSENSE) {
char *cmnd = NCR_700_get_sense_cmnd(SCp->device);
#ifdef NCR_700_DEBUG
@@ -1004,7 +1004,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
* here */
NCR_700_unmap(hostdata, SCp, slot);
dma_unmap_single(hostdata->dev, slot->pCmd,
- sizeof(SCp->cmnd),
+ MAX_COMMAND_SIZE,
DMA_TO_DEVICE);
cmnd[0] = REQUEST_SENSE;
@@ -1901,7 +1901,7 @@ NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
}
slot->resume_offset = 0;
slot->pCmd = dma_map_single(hostdata->dev, SCp->cmnd,
- sizeof(SCp->cmnd), DMA_TO_DEVICE);
+ MAX_COMMAND_SIZE, DMA_TO_DEVICE);
NCR_700_start_command(SCp);
return 0;
}
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 99c57b0c1d5..46d7e400c8b 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -504,10 +504,9 @@ config SCSI_AIC7XXX_OLD
source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
source "drivers/scsi/aic94xx/Kconfig"
-# All the I2O code and drivers do not seem to be 64bit safe.
config SCSI_DPT_I2O
tristate "Adaptec I2O RAID support "
- depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
+ depends on SCSI && PCI && VIRT_TO_BUS
help
This driver supports all of Adaptec's I2O based RAID controllers as
well as the DPT SmartRaid V cards. This is an Adaptec maintained
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 792b2e807bf..ced3eebe252 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -895,7 +895,7 @@ static void inia100_build_scb(struct orc_host * host, struct orc_scb * scb, stru
} else {
scb->tag_msg = 0; /* No tag support */
}
- memcpy(&scb->cdb[0], &cmd->cmnd, scb->cdb_len);
+ memcpy(scb->cdb, cmd->cmnd, scb->cdb_len);
}
/**
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 460d4024c46..aa4e77c2527 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -498,6 +498,11 @@ static void _aac_probe_container2(void * context, struct fib * fibptr)
(le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
(le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
fsa_dev_ptr->valid = 1;
+ /* sense_key holds the current state of the spin-up */
+ if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
+ fsa_dev_ptr->sense_data.sense_key = NOT_READY;
+ else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY)
+ fsa_dev_ptr->sense_data.sense_key = NO_SENSE;
fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
fsa_dev_ptr->size
= ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
@@ -1509,20 +1514,35 @@ static void io_callback(void *context, struct fib * fibptr)
scsi_dma_unmap(scsicmd);
readreply = (struct aac_read_reply *)fib_data(fibptr);
- if (le32_to_cpu(readreply->status) == ST_OK)
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
- else {
+ switch (le32_to_cpu(readreply->status)) {
+ case ST_OK:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
+ dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE;
+ break;
+ case ST_NOT_READY:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY,
+ SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0);
+ memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+ min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+ SCSI_SENSE_BUFFERSIZE));
+ break;
+ default:
#ifdef AAC_DETAILED_STATUS_INFO
printk(KERN_WARNING "io_callback: io failed, status = %d\n",
le32_to_cpu(readreply->status));
#endif
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
set_sense(&dev->fsa_dev[cid].sense_data,
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
SCSI_SENSE_BUFFERSIZE));
+ break;
}
aac_fib_complete(fibptr);
aac_fib_free(fibptr);
@@ -1863,6 +1883,84 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
return SCSI_MLQUEUE_HOST_BUSY;
}
+static void aac_start_stop_callback(void *context, struct fib *fibptr)
+{
+ struct scsi_cmnd *scsicmd = context;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
+
+ BUG_ON(fibptr == NULL);
+
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ scsicmd->scsi_done(scsicmd);
+}
+
+static int aac_start_stop(struct scsi_cmnd *scsicmd)
+{
+ int status;
+ struct fib *cmd_fibcontext;
+ struct aac_power_management *pmcmd;
+ struct scsi_device *sdev = scsicmd->device;
+ struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+
+ if (!(aac->supplement_adapter_info.SupportedOptions2 &
+ AAC_OPTION_POWER_MANAGEMENT)) {
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+ }
+
+ if (aac->in_reset)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ /*
+ * Allocate and initialize a Fib
+ */
+ cmd_fibcontext = aac_fib_alloc(aac);
+ if (!cmd_fibcontext)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ aac_fib_init(cmd_fibcontext);
+
+ pmcmd = fib_data(cmd_fibcontext);
+ pmcmd->command = cpu_to_le32(VM_ContainerConfig);
+ pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT);
+ /* Eject bit ignored, not relevant */
+ pmcmd->sub = (scsicmd->cmnd[4] & 1) ?
+ cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT);
+ pmcmd->cid = cpu_to_le32(sdev_id(sdev));
+ pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
+ cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
+
+ /*
+ * Now send the Fib to the adapter
+ */
+ status = aac_fib_send(ContainerCommand,
+ cmd_fibcontext,
+ sizeof(struct aac_power_management),
+ FsaNormal,
+ 0, 1,
+ (fib_callback)aac_start_stop_callback,
+ (void *)scsicmd);
+
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
+
+ aac_fib_complete(cmd_fibcontext);
+ aac_fib_free(cmd_fibcontext);
+ return SCSI_MLQUEUE_HOST_BUSY;
+}
+
/**
* aac_scsi_cmd() - Process SCSI command
* @scsicmd: SCSI command block
@@ -1899,7 +1997,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* If the target container doesn't exist, it may have
* been newly created
*/
- if ((fsa_dev_ptr[cid].valid & 1) == 0) {
+ if (((fsa_dev_ptr[cid].valid & 1) == 0) ||
+ (fsa_dev_ptr[cid].sense_data.sense_key ==
+ NOT_READY)) {
switch (scsicmd->cmnd[0]) {
case SERVICE_ACTION_IN:
if (!(dev->raw_io_interface) ||
@@ -2091,8 +2191,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
/* Do not cache partition table for arrays */
scsicmd->device->removable = 1;
-
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
return 0;
@@ -2187,15 +2287,32 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* These commands are all No-Ops
*/
case TEST_UNIT_READY:
+ if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) {
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ set_sense(&dev->fsa_dev[cid].sense_data,
+ NOT_READY, SENCODE_BECOMING_READY,
+ ASENCODE_BECOMING_READY, 0, 0);
+ memcpy(scsicmd->sense_buffer,
+ &dev->fsa_dev[cid].sense_data,
+ min_t(size_t,
+ sizeof(dev->fsa_dev[cid].sense_data),
+ SCSI_SENSE_BUFFERSIZE));
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+ }
+ /* FALLTHRU */
case RESERVE:
case RELEASE:
case REZERO_UNIT:
case REASSIGN_BLOCKS:
case SEEK_10:
- case START_STOP:
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
return 0;
+
+ case START_STOP:
+ return aac_start_stop(scsicmd);
}
switch (scsicmd->cmnd[0])
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 113ca9c8934..73916adb8f8 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2455
+# define AAC_DRIVER_BUILD 2456
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -34,8 +34,8 @@
#define CONTAINER_TO_ID(cont) (cont)
#define CONTAINER_TO_LUN(cont) (0)
-#define aac_phys_to_logical(x) (x+1)
-#define aac_logical_to_phys(x) (x?x-1:0)
+#define aac_phys_to_logical(x) ((x)+1)
+#define aac_logical_to_phys(x) ((x)?(x)-1:0)
/* #define AAC_DETAILED_STATUS_INFO */
@@ -424,6 +424,8 @@ struct aac_init
*/
__le32 InitFlags; /* flags for supported features */
#define INITFLAGS_NEW_COMM_SUPPORTED 0x00000001
+#define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010
+#define INITFLAGS_DRIVER_SUPPORTS_PM 0x00000020
__le32 MaxIoCommands; /* max outstanding commands */
__le32 MaxIoSize; /* largest I/O command */
__le32 MaxFibSize; /* largest FIB to adapter */
@@ -867,8 +869,10 @@ struct aac_supplement_adapter_info
};
#define AAC_FEATURE_FALCON cpu_to_le32(0x00000010)
#define AAC_FEATURE_JBOD cpu_to_le32(0x08000000)
-#define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001)
-#define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002)
+/* SupportedOptions2 */
+#define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001)
+#define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002)
+#define AAC_OPTION_POWER_MANAGEMENT cpu_to_le32(0x00000004)
#define AAC_SIS_VERSION_V3 3
#define AAC_SIS_SLOT_UNKNOWN 0xFF
@@ -1148,6 +1152,7 @@ struct aac_dev
#define ST_DQUOT 69
#define ST_STALE 70
#define ST_REMOTE 71
+#define ST_NOT_READY 72
#define ST_BADHANDLE 10001
#define ST_NOT_SYNC 10002
#define ST_BAD_COOKIE 10003
@@ -1269,6 +1274,18 @@ struct aac_synchronize_reply {
u8 data[16];
};
+#define CT_POWER_MANAGEMENT 245
+#define CT_PM_START_UNIT 2
+#define CT_PM_STOP_UNIT 3
+#define CT_PM_UNIT_IMMEDIATE 1
+struct aac_power_management {
+ __le32 command; /* VM_ContainerConfig */
+ __le32 type; /* CT_POWER_MANAGEMENT */
+ __le32 sub; /* CT_PM_* */
+ __le32 cid;
+ __le32 parm; /* CT_PM_sub_* */
+};
+
#define CT_PAUSE_IO 65
#define CT_RELEASE_IO 66
struct aac_pause {
@@ -1536,6 +1553,7 @@ struct aac_mntent {
#define FSCS_NOTCLEAN 0x0001 /* fsck is necessary before mounting */
#define FSCS_READONLY 0x0002 /* possible result of broken mirror */
#define FSCS_HIDDEN 0x0004 /* should be ignored - set during a clear */
+#define FSCS_NOT_READY 0x0008 /* Array spinning up to fulfil request */
struct aac_query_mount {
__le32 command;
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 294a802450b..cbac0635510 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -97,6 +97,8 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
}
+ init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME |
+ INITFLAGS_DRIVER_SUPPORTS_PM);
init->MaxIoCommands = cpu_to_le32(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
init->MaxFibSize = cpu_to_le32(dev->max_fib_size);
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index ef67816a6fe..289304aab69 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -515,7 +515,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
udelay(5);
}
- } else if (down_interruptible(&fibptr->event_wait) == 0) {
+ } else if (down_interruptible(&fibptr->event_wait)) {
fibptr->done = 2;
up(&fibptr->event_wait);
}
@@ -906,15 +906,22 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
case AifEnAddJBOD:
case AifEnDeleteJBOD:
container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
- if ((container >> 28))
+ if ((container >> 28)) {
+ container = (u32)-1;
break;
+ }
channel = (container >> 24) & 0xF;
- if (channel >= dev->maximum_num_channels)
+ if (channel >= dev->maximum_num_channels) {
+ container = (u32)-1;
break;
+ }
id = container & 0xFFFF;
- if (id >= dev->maximum_num_physicals)
+ if (id >= dev->maximum_num_physicals) {
+ container = (u32)-1;
break;
+ }
lun = (container >> 16) & 0xFF;
+ container = (u32)-1;
channel = aac_phys_to_logical(channel);
device_config_needed =
(((__le32 *)aifcmd->data)[0] ==
@@ -933,13 +940,18 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
case EM_DRIVE_REMOVAL:
container = le32_to_cpu(
((__le32 *)aifcmd->data)[2]);
- if ((container >> 28))
+ if ((container >> 28)) {
+ container = (u32)-1;
break;
+ }
channel = (container >> 24) & 0xF;
- if (channel >= dev->maximum_num_channels)
+ if (channel >= dev->maximum_num_channels) {
+ container = (u32)-1;
break;
+ }
id = container & 0xFFFF;
lun = (container >> 16) & 0xFF;
+ container = (u32)-1;
if (id >= dev->maximum_num_physicals) {
/* legacy dev_t ? */
if ((0x2000 <= id) || lun || channel ||
@@ -1025,9 +1037,10 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
break;
}
+ container = 0;
+retry_next:
if (device_config_needed == NOTHING)
- for (container = 0; container < dev->maximum_num_containers;
- ++container) {
+ for (; container < dev->maximum_num_containers; ++container) {
if ((dev->fsa_dev[container].config_waiting_on == 0) &&
(dev->fsa_dev[container].config_needed != NOTHING) &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) {
@@ -1110,6 +1123,11 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
}
if (device_config_needed == ADD)
scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
+ if (channel == CONTAINER_CHANNEL) {
+ container++;
+ device_config_needed = NOTHING;
+ goto retry_next;
+ }
}
static int _aac_reset_adapter(struct aac_dev *aac, int forced)
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index c109f63f827..1f7c83607f8 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -401,6 +401,8 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
static int aac_slave_configure(struct scsi_device *sdev)
{
struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+ if (aac->jbod && (sdev->type == TYPE_DISK))
+ sdev->removable = 1;
if ((sdev->type == TYPE_DISK) &&
(sdev_channel(sdev) != CONTAINER_CHANNEL) &&
(!aac->jbod || sdev->inq_periph_qual) &&
@@ -809,6 +811,12 @@ static ssize_t aac_show_flags(struct device *cdev,
"SAI_READ_CAPACITY_16\n");
if (dev->jbod)
len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n");
+ if (dev->supplement_adapter_info.SupportedOptions2 &
+ AAC_OPTION_POWER_MANAGEMENT)
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "SUPPORTED_POWER_MANAGEMENT\n");
+ if (dev->msi)
+ len += snprintf(buf + len, PAGE_SIZE - len, "PCI_HAS_MSI\n");
return len;
}
@@ -1106,7 +1114,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
aac->pdev = pdev;
aac->name = aac_driver_template.name;
aac->id = shost->unique_id;
- aac->cardtype = index;
+ aac->cardtype = index;
INIT_LIST_HEAD(&aac->entry);
aac->fibs = kmalloc(sizeof(struct fib) * (shost->can_queue + AAC_NUM_MGT_FIB), GFP_KERNEL);
@@ -1146,19 +1154,19 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
goto out_deinit;
/*
- * Lets override negotiations and drop the maximum SG limit to 34
- */
+ * Lets override negotiations and drop the maximum SG limit to 34
+ */
if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) &&
(shost->sg_tablesize > 34)) {
shost->sg_tablesize = 34;
shost->max_sectors = (shost->sg_tablesize * 8) + 112;
- }
+ }
- if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
+ if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
(shost->sg_tablesize > 17)) {
shost->sg_tablesize = 17;
shost->max_sectors = (shost->sg_tablesize * 8) + 112;
- }
+ }
error = pci_set_dma_max_seg_size(pdev,
(aac->adapter_info.options & AAC_OPT_NEW_COMM) ?
@@ -1174,7 +1182,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
else
aac->printf_enabled = 0;
- /*
+ /*
* max channel will be the physical channels plus 1 virtual channel
* all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
* physical channels are address by their actual physical number+1
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 90f5e0a6f2e..2a730c470f6 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -529,10 +529,10 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
/* The first entry, 0, is used for dynamic ids, the rest for devices
* we know about.
*/
-static struct asd_pcidev_struct {
+static const struct asd_pcidev_struct {
const char * name;
int (*setup)(struct asd_ha_struct *asd_ha);
-} asd_pcidev_data[] = {
+} asd_pcidev_data[] __devinitconst = {
/* Id 0 is used for dynamic ids. */
{ .name = "Adaptec AIC-94xx SAS/SATA Host Adapter",
.setup = asd_aic9410_setup
@@ -735,7 +735,7 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
static int __devinit asd_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
- struct asd_pcidev_struct *asd_dev;
+ const struct asd_pcidev_struct *asd_dev;
unsigned asd_id = (unsigned) id->driver_data;
struct asd_ha_struct *asd_ha;
struct Scsi_Host *shost;
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 403a7f2d8f9..9785d738419 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -28,7 +28,6 @@
#define SERVICE_ACTION_OUT_12 0xa9
#define SERVICE_ACTION_IN_16 0x9e
#define SERVICE_ACTION_OUT_16 0x9f
-#define VARIABLE_LENGTH_CMD 0x7f
@@ -210,7 +209,7 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
- len = cdbp[7] + 8;
+ len = scsi_varlen_cdb_length(cdbp);
if (len < 10) {
printk("short variable length command, "
"len=%d ext_len=%d", len, cdb_len);
@@ -300,7 +299,7 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
- len = cdbp[7] + 8;
+ len = scsi_varlen_cdb_length(cdbp);
if (len < 10) {
printk("short opcode=0x%x command, len=%d "
"ext_len=%d", cdb0, len, cdb_len);
@@ -335,10 +334,7 @@ void __scsi_print_command(unsigned char *cdb)
int k, len;
print_opcode_name(cdb, 0);
- if (VARIABLE_LENGTH_CMD == cdb[0])
- len = cdb[7] + 8;
- else
- len = COMMAND_SIZE(cdb[0]);
+ len = scsi_command_size(cdb);
/* print out all bytes in cdb */
for (k = 0; k < len; ++k)
printk(" %02x", cdb[k]);
diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h
index cc784e8f6e9..f60236721e0 100644
--- a/drivers/scsi/dpt/dpti_ioctl.h
+++ b/drivers/scsi/dpt/dpti_ioctl.h
@@ -89,7 +89,7 @@ typedef struct {
int njobs; /* # of jobs sent to HA */
int qdepth; /* Controller queue depth. */
int wakebase; /* mpx wakeup base index. */
- uLONG SGsize; /* Scatter/Gather list size. */
+ uINT SGsize; /* Scatter/Gather list size. */
unsigned heads; /* heads for drives on cntlr. */
unsigned sectors; /* sectors for drives on cntlr. */
uCHAR do_drive32; /* Flag for Above 16 MB Ability */
@@ -97,8 +97,8 @@ typedef struct {
char idPAL[4]; /* 4 Bytes Of The ID Pal */
uCHAR primary; /* 1 For Primary, 0 For Secondary */
uCHAR eataVersion; /* EATA Version */
- uLONG cpLength; /* EATA Command Packet Length */
- uLONG spLength; /* EATA Status Packet Length */
+ uINT cpLength; /* EATA Command Packet Length */
+ uINT spLength; /* EATA Status Packet Length */
uCHAR drqNum; /* DRQ Index (0,5,6,7) */
uCHAR flag1; /* EATA Flags 1 (Byte 9) */
uCHAR flag2; /* EATA Flags 2 (Byte 30) */
@@ -107,23 +107,23 @@ typedef struct {
typedef struct {
uSHORT length; // Remaining length of this
uSHORT drvrHBAnum; // Relative HBA # used by the driver
- uLONG baseAddr; // Base I/O address
+ uINT baseAddr; // Base I/O address
uSHORT blinkState; // Blink LED state (0=Not in blink LED)
uCHAR pciBusNum; // PCI Bus # (Optional)
uCHAR pciDeviceNum; // PCI Device # (Optional)
uSHORT hbaFlags; // Miscellaneous HBA flags
uSHORT Interrupt; // Interrupt set for this device.
# if (defined(_DPT_ARC))
- uLONG baseLength;
+ uINT baseLength;
ADAPTER_OBJECT *AdapterObject;
LARGE_INTEGER DmaLogicalAddress;
PVOID DmaVirtualAddress;
LARGE_INTEGER ReplyLogicalAddress;
PVOID ReplyVirtualAddress;
# else
- uLONG reserved1; // Reserved for future expansion
- uLONG reserved2; // Reserved for future expansion
- uLONG reserved3; // Reserved for future expansion
+ uINT reserved1; // Reserved for future expansion
+ uINT reserved2; // Reserved for future expansion
+ uINT reserved3; // Reserved for future expansion
# endif
} drvrHBAinfo_S;
diff --git a/drivers/scsi/dpt/dptsig.h b/drivers/scsi/dpt/dptsig.h
index 94bc894d120..72c8992fdf2 100644
--- a/drivers/scsi/dpt/dptsig.h
+++ b/drivers/scsi/dpt/dptsig.h
@@ -33,11 +33,7 @@
/* to make sure we are talking the same size under all OS's */
typedef unsigned char sigBYTE;
typedef unsigned short sigWORD;
-#if (defined(_MULTI_DATAMODEL) && defined(sun) && !defined(_ILP32))
-typedef uint32_t sigLONG;
-#else
-typedef unsigned long sigLONG;
-#endif
+typedef unsigned int sigINT;
/*
* use sigWORDLittleEndian for:
@@ -300,7 +296,7 @@ typedef struct dpt_sig {
sigBYTE dsFiletype; /* type of file */
sigBYTE dsFiletypeFlags; /* flags to specify load type, etc. */
sigBYTE dsOEM; /* OEM file was created for */
- sigLONG dsOS; /* which Operating systems */
+ sigINT dsOS; /* which Operating systems */
sigWORD dsCapabilities; /* RAID levels, etc. */
sigWORD dsDeviceSupp; /* Types of SCSI devices supported */
sigWORD dsAdapterSupp; /* DPT adapter families supported */
diff --git a/drivers/scsi/dpt/sys_info.h b/drivers/scsi/dpt/sys_info.h
index d23b70c8c76..a90c4cb8ea8 100644
--- a/drivers/scsi/dpt/sys_info.h
+++ b/drivers/scsi/dpt/sys_info.h
@@ -145,8 +145,8 @@
uCHAR smartROMRevision;
uSHORT flags; /* See bit definitions above */
uSHORT conventionalMemSize; /* in KB */
- uLONG extendedMemSize; /* in KB */
- uLONG osType; /* Same as DPTSIG's definition */
+ uINT extendedMemSize; /* in KB */
+ uINT osType; /* Same as DPTSIG's definition */
uCHAR osMajorVersion;
uCHAR osMinorVersion; /* The OS version */
uCHAR osRevision;
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index ac92ac143b4..0fb5bf4c43a 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -29,11 +29,6 @@
/*#define DEBUG 1 */
/*#define UARTDELAY 1 */
-/* On the real kernel ADDR32 should always be zero for 2.4. GFP_HIGH allocates
- high pages. Keep the macro around because of the broken unmerged ia64 tree */
-
-#define ADDR32 (0)
-
#include <linux/module.h>
MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn");
@@ -108,27 +103,28 @@ static dpt_sig_S DPTI_sig = {
static DEFINE_MUTEX(adpt_configuration_lock);
-static struct i2o_sys_tbl *sys_tbl = NULL;
-static int sys_tbl_ind = 0;
-static int sys_tbl_len = 0;
+static struct i2o_sys_tbl *sys_tbl;
+static dma_addr_t sys_tbl_pa;
+static int sys_tbl_ind;
+static int sys_tbl_len;
static adpt_hba* hba_chain = NULL;
static int hba_count = 0;
+static struct class *adpt_sysfs_class;
+
+#ifdef CONFIG_COMPAT
+static long compat_adpt_ioctl(struct file *, unsigned int, unsigned long);
+#endif
+
static const struct file_operations adpt_fops = {
.ioctl = adpt_ioctl,
.open = adpt_open,
- .release = adpt_close
-};
-
-#ifdef REBOOT_NOTIFIER
-static struct notifier_block adpt_reboot_notifier =
-{
- adpt_reboot_event,
- NULL,
- 0
-};
+ .release = adpt_close,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_adpt_ioctl,
#endif
+};
/* Structures and definitions for synchronous message posting.
* See adpt_i2o_post_wait() for description
@@ -151,6 +147,21 @@ static DEFINE_SPINLOCK(adpt_post_wait_lock);
*============================================================================
*/
+static inline int dpt_dma64(adpt_hba *pHba)
+{
+ return (sizeof(dma_addr_t) > 4 && (pHba)->dma64);
+}
+
+static inline u32 dma_high(dma_addr_t addr)
+{
+ return upper_32_bits(addr);
+}
+
+static inline u32 dma_low(dma_addr_t addr)
+{
+ return (u32)addr;
+}
+
static u8 adpt_read_blink_led(adpt_hba* host)
{
if (host->FwDebugBLEDflag_P) {
@@ -178,8 +189,6 @@ static int adpt_detect(struct scsi_host_template* sht)
struct pci_dev *pDev = NULL;
adpt_hba* pHba;
- adpt_init();
-
PINFO("Detecting Adaptec I2O RAID controllers...\n");
/* search for all Adatpec I2O RAID cards */
@@ -247,13 +256,29 @@ rebuild_sys_tab:
adpt_inquiry(pHba);
}
+ adpt_sysfs_class = class_create(THIS_MODULE, "dpt_i2o");
+ if (IS_ERR(adpt_sysfs_class)) {
+ printk(KERN_WARNING"dpti: unable to create dpt_i2o class\n");
+ adpt_sysfs_class = NULL;
+ }
+
for (pHba = hba_chain; pHba; pHba = pHba->next) {
- if( adpt_scsi_register(pHba,sht) < 0){
+ if (adpt_scsi_host_alloc(pHba, sht) < 0){
adpt_i2o_delete_hba(pHba);
continue;
}
pHba->initialized = TRUE;
pHba->state &= ~DPTI_STATE_RESET;
+ if (adpt_sysfs_class) {
+ struct device *dev = device_create(adpt_sysfs_class,
+ NULL, MKDEV(DPTI_I2O_MAJOR, pHba->unit),
+ "dpti%d", pHba->unit);
+ if (IS_ERR(dev)) {
+ printk(KERN_WARNING"dpti%d: unable to "
+ "create device in dpt_i2o class\n",
+ pHba->unit);
+ }
+ }
}
// Register our control device node
@@ -282,7 +307,7 @@ static int adpt_release(struct Scsi_Host *host)
static void adpt_inquiry(adpt_hba* pHba)
{
- u32 msg[14];
+ u32 msg[17];
u32 *mptr;
u32 *lenptr;
int direction;
@@ -290,11 +315,12 @@ static void adpt_inquiry(adpt_hba* pHba)
u32 len;
u32 reqlen;
u8* buf;
+ dma_addr_t addr;
u8 scb[16];
s32 rcode;
memset(msg, 0, sizeof(msg));
- buf = kmalloc(80,GFP_KERNEL|ADDR32);
+ buf = dma_alloc_coherent(&pHba->pDev->dev, 80, &addr, GFP_KERNEL);
if(!buf){
printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name);
return;
@@ -305,7 +331,10 @@ static void adpt_inquiry(adpt_hba* pHba)
direction = 0x00000000;
scsidir =0x40000000; // DATA IN (iop<--dev)
- reqlen = 14; // SINGLE SGE
+ if (dpt_dma64(pHba))
+ reqlen = 17; // SINGLE SGE, 64 bit
+ else
+ reqlen = 14; // SINGLE SGE, 32 bit
/* Stick the headers on */
msg[0] = reqlen<<16 | SGL_OFFSET_12;
msg[1] = (0xff<<24|HOST_TID<<12|ADAPTER_TID);
@@ -338,8 +367,16 @@ static void adpt_inquiry(adpt_hba* pHba)
/* Now fill in the SGList and command */
*lenptr = len;
- *mptr++ = 0xD0000000|direction|len;
- *mptr++ = virt_to_bus(buf);
+ if (dpt_dma64(pHba)) {
+ *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
+ *mptr++ = 1 << PAGE_SHIFT;
+ *mptr++ = 0xD0000000|direction|len;
+ *mptr++ = dma_low(addr);
+ *mptr++ = dma_high(addr);
+ } else {
+ *mptr++ = 0xD0000000|direction|len;
+ *mptr++ = addr;
+ }
// Send it on it's way
rcode = adpt_i2o_post_wait(pHba, msg, reqlen<<2, 120);
@@ -347,7 +384,7 @@ static void adpt_inquiry(adpt_hba* pHba)
sprintf(pHba->detail, "Adaptec I2O RAID");
printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode);
if (rcode != -ETIME && rcode != -EINTR)
- kfree(buf);
+ dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
} else {
memset(pHba->detail, 0, sizeof(pHba->detail));
memcpy(&(pHba->detail), "Vendor: Adaptec ", 16);
@@ -356,7 +393,7 @@ static void adpt_inquiry(adpt_hba* pHba)
memcpy(&(pHba->detail[40]), " FW: ", 4);
memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4);
pHba->detail[48] = '\0'; /* precautionary */
- kfree(buf);
+ dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
}
adpt_i2o_status_get(pHba);
return ;
@@ -632,6 +669,91 @@ stop_output:
return len;
}
+/*
+ * Turn a struct scsi_cmnd * into a unique 32 bit 'context'.
+ */
+static u32 adpt_cmd_to_context(struct scsi_cmnd *cmd)
+{
+ return (u32)cmd->serial_number;
+}
+
+/*
+ * Go from a u32 'context' to a struct scsi_cmnd * .
+ * This could probably be made more efficient.
+ */
+static struct scsi_cmnd *
+ adpt_cmd_from_context(adpt_hba * pHba, u32 context)
+{
+ struct scsi_cmnd * cmd;
+ struct scsi_device * d;
+
+ if (context == 0)
+ return NULL;
+
+ spin_unlock(pHba->host->host_lock);
+ shost_for_each_device(d, pHba->host) {
+ unsigned long flags;
+ spin_lock_irqsave(&d->list_lock, flags);
+ list_for_each_entry(cmd, &d->cmd_list, list) {
+ if (((u32)cmd->serial_number == context)) {
+ spin_unlock_irqrestore(&d->list_lock, flags);
+ scsi_device_put(d);
+ spin_lock(pHba->host->host_lock);
+ return cmd;
+ }
+ }
+ spin_unlock_irqrestore(&d->list_lock, flags);
+ }
+ spin_lock(pHba->host->host_lock);
+
+ return NULL;
+}
+
+/*
+ * Turn a pointer to ioctl reply data into an u32 'context'
+ */
+static u32 adpt_ioctl_to_context(adpt_hba * pHba, void *reply)
+{
+#if BITS_PER_LONG == 32
+ return (u32)(unsigned long)reply;
+#else
+ ulong flags = 0;
+ u32 nr, i;
+
+ spin_lock_irqsave(pHba->host->host_lock, flags);
+ nr = ARRAY_SIZE(pHba->ioctl_reply_context);
+ for (i = 0; i < nr; i++) {
+ if (pHba->ioctl_reply_context[i] == NULL) {
+ pHba->ioctl_reply_context[i] = reply;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(pHba->host->host_lock, flags);
+ if (i >= nr) {
+ kfree (reply);
+ printk(KERN_WARNING"%s: Too many outstanding "
+ "ioctl commands\n", pHba->name);
+ return (u32)-1;
+ }
+
+ return i;
+#endif
+}
+
+/*
+ * Go from an u32 'context' to a pointer to ioctl reply data.
+ */
+static void *adpt_ioctl_from_context(adpt_hba *pHba, u32 context)
+{
+#if BITS_PER_LONG == 32
+ return (void *)(unsigned long)context;
+#else
+ void *p = pHba->ioctl_reply_context[context];
+ pHba->ioctl_reply_context[context] = NULL;
+
+ return p;
+#endif
+}
/*===========================================================================
* Error Handling routines
@@ -660,7 +782,7 @@ static int adpt_abort(struct scsi_cmnd * cmd)
msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|dptdevice->tid;
msg[2] = 0;
msg[3]= 0;
- msg[4] = (u32)cmd;
+ msg[4] = adpt_cmd_to_context(cmd);
if (pHba->host)
spin_lock_irq(pHba->host->host_lock);
rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER);
@@ -861,27 +983,6 @@ static void adpt_i2o_sys_shutdown(void)
printk(KERN_INFO "Adaptec I2O controllers down.\n");
}
-/*
- * reboot/shutdown notification.
- *
- * - Quiesce each IOP in the system
- *
- */
-
-#ifdef REBOOT_NOTIFIER
-static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p)
-{
-
- if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
- return NOTIFY_DONE;
-
- adpt_i2o_sys_shutdown();
-
- return NOTIFY_DONE;
-}
-#endif
-
-
static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev)
{
@@ -893,6 +994,7 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
u32 hba_map1_area_size = 0;
void __iomem *base_addr_virt = NULL;
void __iomem *msg_addr_virt = NULL;
+ int dma64 = 0;
int raptorFlag = FALSE;
@@ -906,9 +1008,21 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
}
pci_set_master(pDev);
- if (pci_set_dma_mask(pDev, DMA_32BIT_MASK))
+
+ /*
+ * See if we should enable dma64 mode.
+ */
+ if (sizeof(dma_addr_t) > 4 &&
+ pci_set_dma_mask(pDev, DMA_64BIT_MASK) == 0) {
+ if (dma_get_required_mask(&pDev->dev) > DMA_32BIT_MASK)
+ dma64 = 1;
+ }
+ if (!dma64 && pci_set_dma_mask(pDev, DMA_32BIT_MASK) != 0)
return -EINVAL;
+ /* adapter only supports message blocks below 4GB */
+ pci_set_consistent_dma_mask(pDev, DMA_32BIT_MASK);
+
base_addr0_phys = pci_resource_start(pDev,0);
hba_map0_area_size = pci_resource_len(pDev,0);
@@ -929,6 +1043,25 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
raptorFlag = TRUE;
}
+#if BITS_PER_LONG == 64
+ /*
+ * The original Adaptec 64 bit driver has this comment here:
+ * "x86_64 machines need more optimal mappings"
+ *
+ * I assume some HBAs report ridiculously large mappings
+ * and we need to limit them on platforms with IOMMUs.
+ */
+ if (raptorFlag == TRUE) {
+ if (hba_map0_area_size > 128)
+ hba_map0_area_size = 128;
+ if (hba_map1_area_size > 524288)
+ hba_map1_area_size = 524288;
+ } else {
+ if (hba_map0_area_size > 524288)
+ hba_map0_area_size = 524288;
+ }
+#endif
+
base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size);
if (!base_addr_virt) {
pci_release_regions(pDev);
@@ -991,16 +1124,22 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
pHba->state = DPTI_STATE_RESET;
pHba->pDev = pDev;
pHba->devices = NULL;
+ pHba->dma64 = dma64;
// Initializing the spinlocks
spin_lock_init(&pHba->state_lock);
spin_lock_init(&adpt_post_wait_lock);
if(raptorFlag == 0){
- printk(KERN_INFO"Adaptec I2O RAID controller %d at %p size=%x irq=%d\n",
- hba_count-1, base_addr_virt, hba_map0_area_size, pDev->irq);
+ printk(KERN_INFO "Adaptec I2O RAID controller"
+ " %d at %p size=%x irq=%d%s\n",
+ hba_count-1, base_addr_virt,
+ hba_map0_area_size, pDev->irq,
+ dma64 ? " (64-bit DMA)" : "");
} else {
- printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d\n",hba_count-1, pDev->irq);
+ printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d%s\n",
+ hba_count-1, pDev->irq,
+ dma64 ? " (64-bit DMA)" : "");
printk(KERN_INFO" BAR0 %p - size= %x\n",base_addr_virt,hba_map0_area_size);
printk(KERN_INFO" BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size);
}
@@ -1053,10 +1192,26 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
if(pHba->msg_addr_virt != pHba->base_addr_virt){
iounmap(pHba->msg_addr_virt);
}
- kfree(pHba->hrt);
- kfree(pHba->lct);
- kfree(pHba->status_block);
- kfree(pHba->reply_pool);
+ if(pHba->FwDebugBuffer_P)
+ iounmap(pHba->FwDebugBuffer_P);
+ if(pHba->hrt) {
+ dma_free_coherent(&pHba->pDev->dev,
+ pHba->hrt->num_entries * pHba->hrt->entry_len << 2,
+ pHba->hrt, pHba->hrt_pa);
+ }
+ if(pHba->lct) {
+ dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
+ pHba->lct, pHba->lct_pa);
+ }
+ if(pHba->status_block) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(i2o_status_block),
+ pHba->status_block, pHba->status_block_pa);
+ }
+ if(pHba->reply_pool) {
+ dma_free_coherent(&pHba->pDev->dev,
+ pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+ pHba->reply_pool, pHba->reply_pool_pa);
+ }
for(d = pHba->devices; d ; d = next){
next = d->next;
@@ -1075,23 +1230,19 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
pci_dev_put(pHba->pDev);
kfree(pHba);
+ if (adpt_sysfs_class)
+ device_destroy(adpt_sysfs_class,
+ MKDEV(DPTI_I2O_MAJOR, pHba->unit));
+
if(hba_count <= 0){
unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER);
+ if (adpt_sysfs_class) {
+ class_destroy(adpt_sysfs_class);
+ adpt_sysfs_class = NULL;
+ }
}
}
-
-static int adpt_init(void)
-{
- printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
-#ifdef REBOOT_NOTIFIER
- register_reboot_notifier(&adpt_reboot_notifier);
-#endif
-
- return 0;
-}
-
-
static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun)
{
struct adpt_device* d;
@@ -1283,6 +1434,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
{
u32 msg[8];
u8* status;
+ dma_addr_t addr;
u32 m = EMPTY_QUEUE ;
ulong timeout = jiffies + (TMOUT_IOPRESET*HZ);
@@ -1305,12 +1457,13 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
schedule_timeout_uninterruptible(1);
} while (m == EMPTY_QUEUE);
- status = kzalloc(4, GFP_KERNEL|ADDR32);
+ status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
if(status == NULL) {
adpt_send_nop(pHba, m);
printk(KERN_ERR"IOP reset failed - no free memory.\n");
return -ENOMEM;
}
+ memset(status,0,4);
msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
@@ -1318,8 +1471,8 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
msg[3]=0;
msg[4]=0;
msg[5]=0;
- msg[6]=virt_to_bus(status);
- msg[7]=0;
+ msg[6]=dma_low(addr);
+ msg[7]=dma_high(addr);
memcpy_toio(pHba->msg_addr_virt+m, msg, sizeof(msg));
wmb();
@@ -1329,7 +1482,10 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
while(*status == 0){
if(time_after(jiffies,timeout)){
printk(KERN_WARNING"%s: IOP Reset Timeout\n",pHba->name);
- kfree(status);
+ /* We lose 4 bytes of "status" here, but we cannot
+ free these because controller may awake and corrupt
+ those bytes at any time */
+ /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
return -ETIMEDOUT;
}
rmb();
@@ -1348,6 +1504,10 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
}
if(time_after(jiffies,timeout)){
printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name);
+ /* We lose 4 bytes of "status" here, but we
+ cannot free these because controller may
+ awake and corrupt those bytes at any time */
+ /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
return -ETIMEDOUT;
}
schedule_timeout_uninterruptible(1);
@@ -1364,7 +1524,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
PDEBUG("%s: Reset completed.\n", pHba->name);
}
- kfree(status);
+ dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
#ifdef UARTDELAY
// This delay is to allow someone attached to the card through the debug UART to
// set up the dump levels that they want before the rest of the initialization sequence
@@ -1636,6 +1796,7 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
u32 i = 0;
u32 rcode = 0;
void *p = NULL;
+ dma_addr_t addr;
ulong flags = 0;
memset(&msg, 0, MAX_MESSAGE_SIZE*4);
@@ -1668,10 +1829,13 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
}
sg_offset = (msg[0]>>4)&0xf;
msg[2] = 0x40000000; // IOCTL context
- msg[3] = (u32)reply;
+ msg[3] = adpt_ioctl_to_context(pHba, reply);
+ if (msg[3] == (u32)-1)
+ return -EBUSY;
+
memset(sg_list,0, sizeof(sg_list[0])*pHba->sg_tablesize);
if(sg_offset) {
- // TODO 64bit fix
+ // TODO add 64 bit API
struct sg_simple_element *sg = (struct sg_simple_element*) (msg+sg_offset);
sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
if (sg_count > pHba->sg_tablesize){
@@ -1690,7 +1854,7 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
}
sg_size = sg[i].flag_count & 0xffffff;
/* Allocate memory for the transfer */
- p = kmalloc(sg_size, GFP_KERNEL|ADDR32);
+ p = dma_alloc_coherent(&pHba->pDev->dev, sg_size, &addr, GFP_KERNEL);
if(!p) {
printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
pHba->name,sg_size,i,sg_count);
@@ -1700,15 +1864,15 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame.
/* Copy in the user's SG buffer if necessary */
if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) {
- // TODO 64bit fix
- if (copy_from_user(p,(void __user *)sg[i].addr_bus, sg_size)) {
+ // sg_simple_element API is 32 bit
+ if (copy_from_user(p,(void __user *)(ulong)sg[i].addr_bus, sg_size)) {
printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i);
rcode = -EFAULT;
goto cleanup;
}
}
- //TODO 64bit fix
- sg[i].addr_bus = (u32)virt_to_bus(p);
+ /* sg_simple_element API is 32 bit, but addr < 4GB */
+ sg[i].addr_bus = addr;
}
}
@@ -1736,7 +1900,7 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
if(sg_offset) {
/* Copy back the Scatter Gather buffers back to user space */
u32 j;
- // TODO 64bit fix
+ // TODO add 64 bit API
struct sg_simple_element* sg;
int sg_size;
@@ -1756,14 +1920,14 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
}
sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
- // TODO 64bit fix
+ // TODO add 64 bit API
sg = (struct sg_simple_element*)(msg + sg_offset);
for (j = 0; j < sg_count; j++) {
/* Copy out the SG list to user's buffer if necessary */
if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) {
sg_size = sg[j].flag_count & 0xffffff;
- // TODO 64bit fix
- if (copy_to_user((void __user *)sg[j].addr_bus,sg_list[j], sg_size)) {
+ // sg_simple_element API is 32 bit
+ if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) {
printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus);
rcode = -EFAULT;
goto cleanup;
@@ -1787,12 +1951,17 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
cleanup:
- if (rcode != -ETIME && rcode != -EINTR)
+ if (rcode != -ETIME && rcode != -EINTR) {
+ struct sg_simple_element *sg =
+ (struct sg_simple_element*) (msg +sg_offset);
kfree (reply);
- while(sg_index) {
- if(sg_list[--sg_index]) {
- if (rcode != -ETIME && rcode != -EINTR)
- kfree(sg_list[sg_index]);
+ while(sg_index) {
+ if(sg_list[--sg_index]) {
+ dma_free_coherent(&pHba->pDev->dev,
+ sg[sg_index].flag_count & 0xffffff,
+ sg_list[sg_index],
+ sg[sg_index].addr_bus);
+ }
}
}
return rcode;
@@ -1978,6 +2147,38 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
return error;
}
+#ifdef CONFIG_COMPAT
+static long compat_adpt_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode;
+ long ret;
+
+ inode = file->f_dentry->d_inode;
+
+ lock_kernel();
+
+ switch(cmd) {
+ case DPT_SIGNATURE:
+ case I2OUSRCMD:
+ case DPT_CTRLINFO:
+ case DPT_SYSINFO:
+ case DPT_BLINKLED:
+ case I2ORESETCMD:
+ case I2ORESCANCMD:
+ case (DPT_TARGET_BUSY & 0xFFFF):
+ case DPT_TARGET_BUSY:
+ ret = adpt_ioctl(inode, file, cmd, arg);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+ unlock_kernel();
+
+ return ret;
+}
+#endif
static irqreturn_t adpt_isr(int irq, void *dev_id)
{
@@ -2009,7 +2210,16 @@ static irqreturn_t adpt_isr(int irq, void *dev_id)
goto out;
}
}
- reply = bus_to_virt(m);
+ if (pHba->reply_pool_pa <= m &&
+ m < pHba->reply_pool_pa +
+ (pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4)) {
+ reply = (u8 *)pHba->reply_pool +
+ (m - pHba->reply_pool_pa);
+ } else {
+ /* Ick, we should *never* be here */
+ printk(KERN_ERR "dpti: reply frame not from pool\n");
+ reply = (u8 *)bus_to_virt(m);
+ }
if (readl(reply) & MSG_FAIL) {
u32 old_m = readl(reply+28);
@@ -2029,7 +2239,7 @@ static irqreturn_t adpt_isr(int irq, void *dev_id)
}
context = readl(reply+8);
if(context & 0x40000000){ // IOCTL
- void *p = (void *)readl(reply+12);
+ void *p = adpt_ioctl_from_context(pHba, readl(reply+12));
if( p != NULL) {
memcpy_fromio(p, reply, REPLY_FRAME_SIZE * 4);
}
@@ -2043,15 +2253,17 @@ static irqreturn_t adpt_isr(int irq, void *dev_id)
status = I2O_POST_WAIT_OK;
}
if(!(context & 0x40000000)) {
- cmd = (struct scsi_cmnd*) readl(reply+12);
+ cmd = adpt_cmd_from_context(pHba,
+ readl(reply+12));
if(cmd != NULL) {
printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context);
}
}
adpt_i2o_post_wait_complete(context, status);
} else { // SCSI message
- cmd = (struct scsi_cmnd*) readl(reply+12);
+ cmd = adpt_cmd_from_context (pHba, readl(reply+12));
if(cmd != NULL){
+ scsi_dma_unmap(cmd);
if(cmd->serial_number != 0) { // If not timedout
adpt_i2o_to_scsi(reply, cmd);
}
@@ -2072,6 +2284,7 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
int i;
u32 msg[MAX_MESSAGE_SIZE];
u32* mptr;
+ u32* lptr;
u32 *lenptr;
int direction;
int scsidir;
@@ -2079,6 +2292,7 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
u32 len;
u32 reqlen;
s32 rcode;
+ dma_addr_t addr;
memset(msg, 0 , sizeof(msg));
len = scsi_bufflen(cmd);
@@ -2118,7 +2332,7 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
// I2O_CMD_SCSI_EXEC
msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid);
msg[2] = 0;
- msg[3] = (u32)cmd; /* We want the SCSI control block back */
+ msg[3] = adpt_cmd_to_context(cmd); /* Want SCSI control block back */
// Our cards use the transaction context as the tag for queueing
// Adaptec/DPT Private stuff
msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16);
@@ -2136,7 +2350,13 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
memcpy(mptr, cmd->cmnd, cmd->cmd_len);
mptr+=4;
lenptr=mptr++; /* Remember me - fill in when we know */
- reqlen = 14; // SINGLE SGE
+ if (dpt_dma64(pHba)) {
+ reqlen = 16; // SINGLE SGE
+ *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
+ *mptr++ = 1 << PAGE_SHIFT;
+ } else {
+ reqlen = 14; // SINGLE SGE
+ }
/* Now fill in the SGList and command */
nseg = scsi_dma_map(cmd);
@@ -2146,12 +2366,16 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
len = 0;
scsi_for_each_sg(cmd, sg, nseg, i) {
+ lptr = mptr;
*mptr++ = direction|0x10000000|sg_dma_len(sg);
len+=sg_dma_len(sg);
- *mptr++ = sg_dma_address(sg);
+ addr = sg_dma_address(sg);
+ *mptr++ = dma_low(addr);
+ if (dpt_dma64(pHba))
+ *mptr++ = dma_high(addr);
/* Make this an end of list */
if (i == nseg - 1)
- mptr[-2] = direction|0xD0000000|sg_dma_len(sg);
+ *lptr = direction|0xD0000000|sg_dma_len(sg);
}
reqlen = mptr - msg;
*lenptr = len;
@@ -2177,13 +2401,13 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
}
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
+static s32 adpt_scsi_host_alloc(adpt_hba* pHba, struct scsi_host_template *sht)
{
- struct Scsi_Host *host = NULL;
+ struct Scsi_Host *host;
- host = scsi_register(sht, sizeof(adpt_hba*));
+ host = scsi_host_alloc(sht, sizeof(adpt_hba*));
if (host == NULL) {
- printk ("%s: scsi_register returned NULL\n",pHba->name);
+ printk("%s: scsi_host_alloc returned NULL\n", pHba->name);
return -1;
}
host->hostdata[0] = (unsigned long)pHba;
@@ -2200,7 +2424,7 @@ static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
host->max_lun = 256;
host->max_channel = pHba->top_scsi_channel + 1;
host->cmd_per_lun = 1;
- host->unique_id = (uint) pHba;
+ host->unique_id = (u32)sys_tbl_pa + pHba->unit;
host->sg_tablesize = pHba->sg_tablesize;
host->can_queue = pHba->post_fifo_size;
@@ -2640,11 +2864,10 @@ static s32 adpt_send_nop(adpt_hba*pHba,u32 m)
static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
{
u8 *status;
+ dma_addr_t addr;
u32 __iomem *msg = NULL;
int i;
ulong timeout = jiffies + TMOUT_INITOUTBOUND*HZ;
- u32* ptr;
- u32 outbound_frame; // This had to be a 32 bit address
u32 m;
do {
@@ -2663,13 +2886,14 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
- status = kzalloc(4, GFP_KERNEL|ADDR32);
+ status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
if (!status) {
adpt_send_nop(pHba, m);
printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n",
pHba->name);
return -ENOMEM;
}
+ memset(status, 0, 4);
writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]);
writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
@@ -2678,7 +2902,7 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
writel(4096, &msg[4]); /* Host page frame size */
writel((REPLY_FRAME_SIZE)<<16|0x80, &msg[5]); /* Outbound msg frame size and Initcode */
writel(0xD0000004, &msg[6]); /* Simple SG LE, EOB */
- writel(virt_to_bus(status), &msg[7]);
+ writel((u32)addr, &msg[7]);
writel(m, pHba->post_port);
wmb();
@@ -2693,6 +2917,10 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
rmb();
if(time_after(jiffies,timeout)){
printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name);
+ /* We lose 4 bytes of "status" here, but we
+ cannot free these because controller may
+ awake and corrupt those bytes at any time */
+ /* dma_free_coherent(&pHba->pDev->dev, 4, status, addr); */
return -ETIMEDOUT;
}
schedule_timeout_uninterruptible(1);
@@ -2701,25 +2929,30 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
// If the command was successful, fill the fifo with our reply
// message packets
if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) {
- kfree(status);
+ dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
return -2;
}
- kfree(status);
+ dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
- kfree(pHba->reply_pool);
+ if(pHba->reply_pool != NULL) {
+ dma_free_coherent(&pHba->pDev->dev,
+ pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+ pHba->reply_pool, pHba->reply_pool_pa);
+ }
- pHba->reply_pool = kzalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
+ pHba->reply_pool = dma_alloc_coherent(&pHba->pDev->dev,
+ pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+ &pHba->reply_pool_pa, GFP_KERNEL);
if (!pHba->reply_pool) {
printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name);
return -ENOMEM;
}
+ memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4);
- ptr = pHba->reply_pool;
for(i = 0; i < pHba->reply_fifo_size; i++) {
- outbound_frame = (u32)virt_to_bus(ptr);
- writel(outbound_frame, pHba->reply_port);
+ writel(pHba->reply_pool_pa + (i * REPLY_FRAME_SIZE * 4),
+ pHba->reply_port);
wmb();
- ptr += REPLY_FRAME_SIZE;
}
adpt_i2o_status_get(pHba);
return 0;
@@ -2743,11 +2976,11 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
u32 m;
u32 __iomem *msg;
u8 *status_block=NULL;
- ulong status_block_bus;
if(pHba->status_block == NULL) {
- pHba->status_block = (i2o_status_block*)
- kmalloc(sizeof(i2o_status_block),GFP_KERNEL|ADDR32);
+ pHba->status_block = dma_alloc_coherent(&pHba->pDev->dev,
+ sizeof(i2o_status_block),
+ &pHba->status_block_pa, GFP_KERNEL);
if(pHba->status_block == NULL) {
printk(KERN_ERR
"dpti%d: Get Status Block failed; Out of memory. \n",
@@ -2757,7 +2990,6 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
}
memset(pHba->status_block, 0, sizeof(i2o_status_block));
status_block = (u8*)(pHba->status_block);
- status_block_bus = virt_to_bus(pHba->status_block);
timeout = jiffies+TMOUT_GETSTATUS*HZ;
do {
rmb();
@@ -2782,8 +3014,8 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
writel(0, &msg[3]);
writel(0, &msg[4]);
writel(0, &msg[5]);
- writel(((u32)status_block_bus)&0xffffffff, &msg[6]);
- writel(0, &msg[7]);
+ writel( dma_low(pHba->status_block_pa), &msg[6]);
+ writel( dma_high(pHba->status_block_pa), &msg[7]);
writel(sizeof(i2o_status_block), &msg[8]); // 88 bytes
//post message
@@ -2812,7 +3044,17 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
}
// Calculate the Scatter Gather list size
- pHba->sg_tablesize = (pHba->status_block->inbound_frame_size * 4 -40)/ sizeof(struct sg_simple_element);
+ if (dpt_dma64(pHba)) {
+ pHba->sg_tablesize
+ = ((pHba->status_block->inbound_frame_size * 4
+ - 14 * sizeof(u32))
+ / (sizeof(struct sg_simple_element) + sizeof(u32)));
+ } else {
+ pHba->sg_tablesize
+ = ((pHba->status_block->inbound_frame_size * 4
+ - 12 * sizeof(u32))
+ / sizeof(struct sg_simple_element));
+ }
if (pHba->sg_tablesize > SG_LIST_ELEMENTS) {
pHba->sg_tablesize = SG_LIST_ELEMENTS;
}
@@ -2863,7 +3105,9 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
}
do {
if (pHba->lct == NULL) {
- pHba->lct = kmalloc(pHba->lct_size, GFP_KERNEL|ADDR32);
+ pHba->lct = dma_alloc_coherent(&pHba->pDev->dev,
+ pHba->lct_size, &pHba->lct_pa,
+ GFP_KERNEL);
if(pHba->lct == NULL) {
printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
pHba->name);
@@ -2879,7 +3123,7 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
msg[4] = 0xFFFFFFFF; /* All devices */
msg[5] = 0x00000000; /* Report now */
msg[6] = 0xD0000000|pHba->lct_size;
- msg[7] = virt_to_bus(pHba->lct);
+ msg[7] = (u32)pHba->lct_pa;
if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 360))) {
printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n",
@@ -2890,7 +3134,8 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
if ((pHba->lct->table_size << 2) > pHba->lct_size) {
pHba->lct_size = pHba->lct->table_size << 2;
- kfree(pHba->lct);
+ dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
+ pHba->lct, pHba->lct_pa);
pHba->lct = NULL;
}
} while (pHba->lct == NULL);
@@ -2901,13 +3146,19 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
// I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO;
if(adpt_i2o_query_scalar(pHba, 0 , 0x8000, -1, buf, sizeof(buf))>=0) {
pHba->FwDebugBufferSize = buf[1];
- pHba->FwDebugBuffer_P = pHba->base_addr_virt + buf[0];
- pHba->FwDebugFlags_P = pHba->FwDebugBuffer_P + FW_DEBUG_FLAGS_OFFSET;
- pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P + FW_DEBUG_BLED_OFFSET;
- pHba->FwDebugBLEDflag_P = pHba->FwDebugBLEDvalue_P + 1;
- pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P + FW_DEBUG_STR_LENGTH_OFFSET;
- pHba->FwDebugBuffer_P += buf[2];
- pHba->FwDebugFlags = 0;
+ pHba->FwDebugBuffer_P = ioremap(pHba->base_addr_phys + buf[0],
+ pHba->FwDebugBufferSize);
+ if (pHba->FwDebugBuffer_P) {
+ pHba->FwDebugFlags_P = pHba->FwDebugBuffer_P +
+ FW_DEBUG_FLAGS_OFFSET;
+ pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P +
+ FW_DEBUG_BLED_OFFSET;
+ pHba->FwDebugBLEDflag_P = pHba->FwDebugBLEDvalue_P + 1;
+ pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P +
+ FW_DEBUG_STR_LENGTH_OFFSET;
+ pHba->FwDebugBuffer_P += buf[2];
+ pHba->FwDebugFlags = 0;
+ }
}
return 0;
@@ -2915,25 +3166,30 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
static int adpt_i2o_build_sys_table(void)
{
- adpt_hba* pHba = NULL;
+ adpt_hba* pHba = hba_chain;
int count = 0;
+ if (sys_tbl)
+ dma_free_coherent(&pHba->pDev->dev, sys_tbl_len,
+ sys_tbl, sys_tbl_pa);
+
sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs
(hba_count) * sizeof(struct i2o_sys_tbl_entry);
- kfree(sys_tbl);
-
- sys_tbl = kzalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
+ sys_tbl = dma_alloc_coherent(&pHba->pDev->dev,
+ sys_tbl_len, &sys_tbl_pa, GFP_KERNEL);
if (!sys_tbl) {
printk(KERN_WARNING "SysTab Set failed. Out of memory.\n");
return -ENOMEM;
}
+ memset(sys_tbl, 0, sys_tbl_len);
sys_tbl->num_entries = hba_count;
sys_tbl->version = I2OVERSION;
sys_tbl->change_ind = sys_tbl_ind++;
for(pHba = hba_chain; pHba; pHba = pHba->next) {
+ u64 addr;
// Get updated Status Block so we have the latest information
if (adpt_i2o_status_get(pHba)) {
sys_tbl->num_entries--;
@@ -2949,8 +3205,9 @@ static int adpt_i2o_build_sys_table(void)
sys_tbl->iops[count].frame_size = pHba->status_block->inbound_frame_size;
sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
sys_tbl->iops[count].iop_capabilities = pHba->status_block->iop_capabilities;
- sys_tbl->iops[count].inbound_low = (u32)virt_to_bus(pHba->post_port);
- sys_tbl->iops[count].inbound_high = (u32)((u64)virt_to_bus(pHba->post_port)>>32);
+ addr = pHba->base_addr_phys + 0x40;
+ sys_tbl->iops[count].inbound_low = dma_low(addr);
+ sys_tbl->iops[count].inbound_high = dma_high(addr);
count++;
}
@@ -3086,7 +3343,8 @@ static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
do {
if (pHba->hrt == NULL) {
- pHba->hrt=kmalloc(size, GFP_KERNEL|ADDR32);
+ pHba->hrt = dma_alloc_coherent(&pHba->pDev->dev,
+ size, &pHba->hrt_pa, GFP_KERNEL);
if (pHba->hrt == NULL) {
printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", pHba->name);
return -ENOMEM;
@@ -3098,7 +3356,7 @@ static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
msg[2]= 0;
msg[3]= 0;
msg[4]= (0xD0000000 | size); /* Simple transaction */
- msg[5]= virt_to_bus(pHba->hrt); /* Dump it here */
+ msg[5]= (u32)pHba->hrt_pa; /* Dump it here */
if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg),20))) {
printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", pHba->name, ret);
@@ -3106,8 +3364,10 @@ static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
}
if (pHba->hrt->num_entries * pHba->hrt->entry_len << 2 > size) {
- size = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
- kfree(pHba->hrt);
+ int newsize = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
+ dma_free_coherent(&pHba->pDev->dev, size,
+ pHba->hrt, pHba->hrt_pa);
+ size = newsize;
pHba->hrt = NULL;
}
} while(pHba->hrt == NULL);
@@ -3121,33 +3381,54 @@ static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
int group, int field, void *buf, int buflen)
{
u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
- u8 *resblk;
+ u8 *opblk_va;
+ dma_addr_t opblk_pa;
+ u8 *resblk_va;
+ dma_addr_t resblk_pa;
int size;
/* 8 bytes for header */
- resblk = kmalloc(sizeof(u8) * (8+buflen), GFP_KERNEL|ADDR32);
- if (resblk == NULL) {
+ resblk_va = dma_alloc_coherent(&pHba->pDev->dev,
+ sizeof(u8) * (8 + buflen), &resblk_pa, GFP_KERNEL);
+ if (resblk_va == NULL) {
printk(KERN_CRIT "%s: query scalar failed; Out of memory.\n", pHba->name);
return -ENOMEM;
}
+ opblk_va = dma_alloc_coherent(&pHba->pDev->dev,
+ sizeof(opblk), &opblk_pa, GFP_KERNEL);
+ if (opblk_va == NULL) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
+ printk(KERN_CRIT "%s: query operatio failed; Out of memory.\n",
+ pHba->name);
+ return -ENOMEM;
+ }
if (field == -1) /* whole group */
opblk[4] = -1;
+ memcpy(opblk_va, opblk, sizeof(opblk));
size = adpt_i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, pHba, tid,
- opblk, sizeof(opblk), resblk, sizeof(u8)*(8+buflen));
+ opblk_va, opblk_pa, sizeof(opblk),
+ resblk_va, resblk_pa, sizeof(u8)*(8+buflen));
+ dma_free_coherent(&pHba->pDev->dev, sizeof(opblk), opblk_va, opblk_pa);
if (size == -ETIME) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
printk(KERN_WARNING "%s: issue params failed; Timed out.\n", pHba->name);
return -ETIME;
} else if (size == -EINTR) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
printk(KERN_WARNING "%s: issue params failed; Interrupted.\n", pHba->name);
return -EINTR;
}
- memcpy(buf, resblk+8, buflen); /* cut off header */
+ memcpy(buf, resblk_va+8, buflen); /* cut off header */
- kfree(resblk);
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
if (size < 0)
return size;
@@ -3164,10 +3445,11 @@ static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
* ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
*/
static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
- void *opblk, int oplen, void *resblk, int reslen)
+ void *opblk_va, dma_addr_t opblk_pa, int oplen,
+ void *resblk_va, dma_addr_t resblk_pa, int reslen)
{
u32 msg[9];
- u32 *res = (u32 *)resblk;
+ u32 *res = (u32 *)resblk_va;
int wait_status;
msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
@@ -3176,12 +3458,12 @@ static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
msg[3] = 0;
msg[4] = 0;
msg[5] = 0x54000000 | oplen; /* OperationBlock */
- msg[6] = virt_to_bus(opblk);
+ msg[6] = (u32)opblk_pa;
msg[7] = 0xD0000000 | reslen; /* ResultBlock */
- msg[8] = virt_to_bus(resblk);
+ msg[8] = (u32)resblk_pa;
if ((wait_status = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 20))) {
- printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk);
+ printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk_va);
return wait_status; /* -DetailedStatus */
}
@@ -3284,7 +3566,7 @@ static int adpt_i2o_systab_send(adpt_hba* pHba)
* Private i/o space declaration
*/
msg[6] = 0x54000000 | sys_tbl_len;
- msg[7] = virt_to_phys(sys_tbl);
+ msg[7] = (u32)sys_tbl_pa;
msg[8] = 0x54000000 | 0;
msg[9] = 0;
msg[10] = 0xD4000000 | 0;
@@ -3323,11 +3605,10 @@ static static void adpt_delay(int millisec)
#endif
static struct scsi_host_template driver_template = {
+ .module = THIS_MODULE,
.name = "dpt_i2o",
.proc_name = "dpt_i2o",
.proc_info = adpt_proc_info,
- .detect = adpt_detect,
- .release = adpt_release,
.info = adpt_info,
.queuecommand = adpt_queue,
.eh_abort_handler = adpt_abort,
@@ -3341,5 +3622,48 @@ static struct scsi_host_template driver_template = {
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
};
-#include "scsi_module.c"
+
+static int __init adpt_init(void)
+{
+ int error;
+ adpt_hba *pHba, *next;
+
+ printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
+
+ error = adpt_detect(&driver_template);
+ if (error < 0)
+ return error;
+ if (hba_chain == NULL)
+ return -ENODEV;
+
+ for (pHba = hba_chain; pHba; pHba = pHba->next) {
+ error = scsi_add_host(pHba->host, &pHba->pDev->dev);
+ if (error)
+ goto fail;
+ scsi_scan_host(pHba->host);
+ }
+ return 0;
+fail:
+ for (pHba = hba_chain; pHba; pHba = next) {
+ next = pHba->next;
+ scsi_remove_host(pHba->host);
+ }
+ return error;
+}
+
+static void __exit adpt_exit(void)
+{
+ adpt_hba *pHba, *next;
+
+ for (pHba = hba_chain; pHba; pHba = pHba->next)
+ scsi_remove_host(pHba->host);
+ for (pHba = hba_chain; pHba; pHba = next) {
+ next = pHba->next;
+ adpt_release(pHba->host);
+ }
+}
+
+module_init(adpt_init);
+module_exit(adpt_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index fd79068c586..924cd5a5167 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -84,7 +84,6 @@ static int adpt_device_reset(struct scsi_cmnd* cmd);
#define PCI_DPT_DEVICE_ID (0xA501) // DPT PCI I2O Device ID
#define PCI_DPT_RAPTOR_DEVICE_ID (0xA511)
-//#define REBOOT_NOTIFIER 1
/* Debugging macro from Linux Device Drivers - Rubini */
#undef PDEBUG
#ifdef DEBUG
@@ -229,14 +228,19 @@ typedef struct _adpt_hba {
u32 post_fifo_size;
u32 reply_fifo_size;
u32* reply_pool;
+ dma_addr_t reply_pool_pa;
u32 sg_tablesize; // Scatter/Gather List Size.
u8 top_scsi_channel;
u8 top_scsi_id;
u8 top_scsi_lun;
+ u8 dma64;
i2o_status_block* status_block;
+ dma_addr_t status_block_pa;
i2o_hrt* hrt;
+ dma_addr_t hrt_pa;
i2o_lct* lct;
+ dma_addr_t lct_pa;
uint lct_size;
struct i2o_device* devices;
struct adpt_channel channel[MAX_CHANNEL];
@@ -249,6 +253,7 @@ typedef struct _adpt_hba {
void __iomem *FwDebugBLEDflag_P;// Virtual Addr Of FW Debug BLED
void __iomem *FwDebugBLEDvalue_P;// Virtual Addr Of FW Debug BLED
u32 FwDebugFlags;
+ u32 *ioctl_reply_context[4];
} adpt_hba;
struct sg_simple_element {
@@ -264,9 +269,6 @@ static void adpt_i2o_sys_shutdown(void);
static int adpt_init(void);
static int adpt_i2o_build_sys_table(void);
static irqreturn_t adpt_isr(int irq, void *dev_id);
-#ifdef REBOOT_NOTIFIER
-static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p);
-#endif
static void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d);
static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
@@ -275,7 +277,8 @@ static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
static const char *adpt_i2o_get_class_name(int class);
#endif
static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
- void *opblk, int oplen, void *resblk, int reslen);
+ void *opblk, dma_addr_t opblk_pa, int oplen,
+ void *resblk, dma_addr_t resblk_pa, int reslen);
static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout);
static int adpt_i2o_lct_get(adpt_hba* pHba);
static int adpt_i2o_parse_lct(adpt_hba* pHba);
@@ -289,7 +292,7 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba);
static s32 adpt_i2o_hrt_get(adpt_hba* pHba);
static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* dptdevice);
static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd);
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht);
+static s32 adpt_scsi_host_alloc(adpt_hba* pHba,struct scsi_host_template * sht);
static s32 adpt_hba_reset(adpt_hba* pHba);
static s32 adpt_i2o_reset_hba(adpt_hba* pHba);
static s32 adpt_rescan(adpt_hba* pHba);
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index c6d6e7c6559..8e2e964af66 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -465,7 +465,7 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
scp->request = (struct request *)&wait;
scp->timeout_per_command = timeout*HZ;
scp->cmd_len = 12;
- memcpy(scp->cmnd, cmnd, 12);
+ scp->cmnd = cmnd;
cmndinfo.priority = IOCTL_PRI;
cmndinfo.internal_cmd_str = gdtcmd;
cmndinfo.internal_command = 1;
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 5b7be1e9841..aaa48e0c8ed 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -763,9 +763,9 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
scp,
host->host_no, scp->device->channel,
scp->device->id, scp->device->lun,
- *((u32 *)&scp->cmnd),
- *((u32 *)&scp->cmnd + 1),
- *((u32 *)&scp->cmnd + 2),
+ ((u32 *)scp->cmnd)[0],
+ ((u32 *)scp->cmnd)[1],
+ ((u32 *)scp->cmnd)[2],
_req->index, _req->req_virt);
scp->result = 0;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 4a922c57125..ccfd8aca376 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -686,7 +686,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
}
if (cmnd) {
- cmnd->result = rsp->status;
+ cmnd->result |= rsp->status;
if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
memcpy(cmnd->sense_buffer,
rsp->data,
@@ -730,6 +730,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
u16 lun = lun_from_dev(cmnd->device);
u8 out_fmt, in_fmt;
+ cmnd->result = (DID_OK << 16);
evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -738,7 +739,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
srp_cmd = &evt_struct->iu.srp.cmd;
memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
srp_cmd->opcode = SRP_CMD;
- memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
+ memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
srp_cmd->lun = ((u64) lun) << 48;
if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
@@ -1347,6 +1348,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
del_timer(&evt_struct->timer);
+ if (crq->status != VIOSRP_OK && evt_struct->cmnd)
+ evt_struct->cmnd->result = DID_ERROR << 16;
if (evt_struct->done)
evt_struct->done(evt_struct);
else
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
index 90f1a61283a..4c4aadb3e40 100644
--- a/drivers/scsi/ibmvscsi/viosrp.h
+++ b/drivers/scsi/ibmvscsi/viosrp.h
@@ -59,6 +59,15 @@ enum viosrp_crq_formats {
VIOSRP_INLINE_FORMAT = 0x07
};
+enum viosrp_crq_status {
+ VIOSRP_OK = 0x0,
+ VIOSRP_NONRECOVERABLE_ERR = 0x1,
+ VIOSRP_VIOLATES_MAX_XFER = 0x2,
+ VIOSRP_PARTNER_PANIC = 0x3,
+ VIOSRP_DEVICE_BUSY = 0x8,
+ VIOSRP_ADAPTER_FAIL = 0x10
+};
+
struct viosrp_crq {
u8 valid; /* used by RPA */
u8 format; /* SCSI vs out-of-band */
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index dbae3fdb850..e3f739776ba 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -2590,7 +2590,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c
cblk->hastat = 0;
cblk->tastat = 0;
/* Command the command */
- memcpy(&cblk->cdb[0], &cmnd->cmnd, cmnd->cmd_len);
+ memcpy(cblk->cdb, cmnd->cmnd, cmnd->cmd_len);
/* Set up tags */
if (cmnd->device->tagged_supported) { /* Tag Support */
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index de5ae6a6502..999e91ea745 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -2791,7 +2791,7 @@ static ssize_t ipr_store_adapter_state(struct device *dev,
static struct device_attribute ipr_ioa_state_attr = {
.attr = {
- .name = "state",
+ .name = "online_state",
.mode = S_IRUGO | S_IWUSR,
},
.show = ipr_show_adapter_state,
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 820f91fb63b..70a0f11f48b 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -3168,6 +3168,23 @@ megaraid_mbox_support_random_del(adapter_t *adapter)
uint8_t raw_mbox[sizeof(mbox_t)];
int rval;
+ /*
+ * Newer firmware on Dell CERC expect a different
+ * random deletion handling, so disable it.
+ */
+ if (adapter->pdev->vendor == PCI_VENDOR_ID_AMI &&
+ adapter->pdev->device == PCI_DEVICE_ID_AMI_MEGARAID3 &&
+ adapter->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+ adapter->pdev->subsystem_device == PCI_SUBSYS_ID_CERC_ATA100_4CH &&
+ (adapter->fw_version[0] > '6' ||
+ (adapter->fw_version[0] == '6' &&
+ adapter->fw_version[2] > '6') ||
+ (adapter->fw_version[0] == '6'
+ && adapter->fw_version[2] == '6'
+ && adapter->fw_version[3] > '1'))) {
+ con_log(CL_DLEVEL1, ("megaraid: disable random deletion\n"));
+ return 0;
+ }
mbox = (mbox_t *)raw_mbox;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index 626459d1e90..c1d86d961a9 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -88,6 +88,7 @@
#define PCI_SUBSYS_ID_PERC3_QC 0x0471
#define PCI_SUBSYS_ID_PERC3_DC 0x0493
#define PCI_SUBSYS_ID_PERC3_SC 0x0475
+#define PCI_SUBSYS_ID_CERC_ATA100_4CH 0x0511
#define MBOX_MAX_SCSI_CMDS 128 // number of cmds reserved for kernel
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index b937e9cddb2..7d84c8bbcf3 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.03.16-rc1
+ * Version : v00.00.03.20-rc1
*
* Authors:
* (email-id : megaraidlinux@lsi.com)
@@ -2650,12 +2650,13 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
return;
}
+#ifdef CONFIG_PM
/**
* megasas_suspend - driver suspend entry point
* @pdev: PCI device structure
* @state: PCI power state to suspend routine
*/
-static int __devinit
+static int
megasas_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct Scsi_Host *host;
@@ -2687,7 +2688,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
* megasas_resume- driver resume entry point
* @pdev: PCI device structure
*/
-static int __devinit
+static int
megasas_resume(struct pci_dev *pdev)
{
int rval;
@@ -2782,12 +2783,16 @@ fail_ready_state:
return -ENODEV;
}
+#else
+#define megasas_suspend NULL
+#define megasas_resume NULL
+#endif
/**
* megasas_detach_one - PCI hot"un"plug entry point
* @pdev: PCI device structure
*/
-static void megasas_detach_one(struct pci_dev *pdev)
+static void __devexit megasas_detach_one(struct pci_dev *pdev)
{
int i;
struct Scsi_Host *host;
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 3a997eb457b..b0c41e67170 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.03.16-rc1"
-#define MEGASAS_RELDATE "Nov. 07, 2007"
-#define MEGASAS_EXT_VERSION "Thu. Nov. 07 10:09:32 PDT 2007"
+#define MEGASAS_VERSION "00.00.03.20-rc1"
+#define MEGASAS_RELDATE "March 10, 2008"
+#define MEGASAS_EXT_VERSION "Mon. March 10 11:02:31 PDT 2008"
/*
* Device IDs
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
index e55b9037adb..1dd70d7a494 100644
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -2822,7 +2822,9 @@ static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
dev_printk(KERN_DEBUG, &pdev->dev,
"phy[%d] Get Attached Address 0x%llX ,"
" SAS Address 0x%llX\n",
- i, phy->att_dev_sas_addr, phy->dev_sas_addr);
+ i,
+ (unsigned long long)phy->att_dev_sas_addr,
+ (unsigned long long)phy->dev_sas_addr);
dev_printk(KERN_DEBUG, &pdev->dev,
"Rate = %x , type = %d\n",
sas_phy->linkrate, phy->phy_type);
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index ceab4f73caf..c57c94c0ffd 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -8222,7 +8222,7 @@ static void process_waiting_list(struct ncb *np, int sts)
#ifdef DEBUG_WAITING_LIST
if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
#endif
- while (wcmd = waiting_list) {
+ while ((wcmd = waiting_list) != NULL) {
waiting_list = (struct scsi_cmnd *) wcmd->next_wcmd;
wcmd->next_wcmd = NULL;
if (sts == DID_OK) {
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 09ab3eac1c1..fa060932d2b 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2858,7 +2858,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
/* Load SCSI command packet. */
pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
- memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+ memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd));
/* dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
/* Set transfer direction. */
@@ -3127,7 +3127,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
/* Load SCSI command packet. */
pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
- memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+ memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd));
/*dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
/* Set transfer direction. */
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 12d69d7c857..110e776d1a0 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -79,15 +79,6 @@ static void scsi_done(struct scsi_cmnd *cmd);
#define MIN_RESET_PERIOD (15*HZ)
/*
- * Macro to determine the size of SCSI command. This macro takes vendor
- * unique commands into account. SCSI commands in groups 6 and 7 are
- * vendor unique and we will depend upon the command length being
- * supplied correctly in cmd_len.
- */
-#define CDB_SIZE(cmd) (((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
- COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
-
-/*
* Note - the initial logging level can be set here to log events at boot time.
* After the system is up, you may enable logging via the /proc interface.
*/
@@ -469,6 +460,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
if (!cmd) {
scsi_put_host_cmd_pool(gfp_mask);
+ shost->cmd_pool = NULL;
return -ENOMEM;
}
list_add(&cmd->list, &shost->free_list);
@@ -481,6 +473,13 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
*/
void scsi_destroy_command_freelist(struct Scsi_Host *shost)
{
+ /*
+ * If cmd_pool is NULL the free list was not initialized, so
+ * do not attempt to release resources.
+ */
+ if (!shost->cmd_pool)
+ return;
+
while (!list_empty(&shost->free_list)) {
struct scsi_cmnd *cmd;
@@ -701,9 +700,11 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
* Before we queue this command, check if the command
* length exceeds what the host adapter can handle.
*/
- if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {
+ if (cmd->cmd_len > cmd->device->host->max_cmd_len) {
SCSI_LOG_MLQUEUE(3,
- printk("queuecommand : command too long.\n"));
+ printk("queuecommand : command too long. "
+ "cdb_size=%d host->max_cmd_len=%d\n",
+ cmd->cmd_len, cmd->device->host->max_cmd_len));
cmd->result = (DID_ABORT << 16);
scsi_done(cmd);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 1eaba6cd80f..eaf5a8add1b 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -626,7 +626,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
* @scmd: SCSI command structure to hijack
* @ses: structure to save restore information
* @cmnd: CDB to send. Can be NULL if no new cmnd is needed
- * @cmnd_size: size in bytes of @cmnd
+ * @cmnd_size: size in bytes of @cmnd (must be <= BLK_MAX_CDB)
* @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
*
* This function is used to save a scsi command information before re-execution
@@ -648,12 +648,14 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
* command.
*/
ses->cmd_len = scmd->cmd_len;
- memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+ ses->cmnd = scmd->cmnd;
ses->data_direction = scmd->sc_data_direction;
ses->sdb = scmd->sdb;
ses->next_rq = scmd->request->next_rq;
ses->result = scmd->result;
+ scmd->cmnd = ses->eh_cmnd;
+ memset(scmd->cmnd, 0, BLK_MAX_CDB);
memset(&scmd->sdb, 0, sizeof(scmd->sdb));
scmd->request->next_rq = NULL;
@@ -665,14 +667,13 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
scmd->sdb.table.sgl = &ses->sense_sgl;
scmd->sc_data_direction = DMA_FROM_DEVICE;
scmd->sdb.table.nents = 1;
- memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
scmd->cmnd[0] = REQUEST_SENSE;
scmd->cmnd[4] = scmd->sdb.length;
scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
} else {
scmd->sc_data_direction = DMA_NONE;
if (cmnd) {
- memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+ BUG_ON(cmnd_size > BLK_MAX_CDB);
memcpy(scmd->cmnd, cmnd, cmnd_size);
scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
}
@@ -705,7 +706,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
* Restore original data
*/
scmd->cmd_len = ses->cmd_len;
- memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
+ scmd->cmnd = ses->cmnd;
scmd->sc_data_direction = ses->data_direction;
scmd->sdb = ses->sdb;
scmd->request->next_rq = ses->next_rq;
@@ -1775,8 +1776,8 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scmd->request = &req;
memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
- memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
-
+ scmd->cmnd = req.cmd;
+
scmd->scsi_done = scsi_reset_provider_done_command;
memset(&scmd->sdb, 0, sizeof(scmd->sdb));
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index d545ad1cf47..a82d2fe80fb 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -445,7 +445,7 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
scsi_set_resid(cmd, 0);
memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
if (cmd->cmd_len == 0)
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+ cmd->cmd_len = scsi_command_size(cmd->cmnd);
}
void scsi_device_unbusy(struct scsi_device *sdev)
@@ -1094,6 +1094,8 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
cmd->tag = req->tag;
cmd->request = req;
+ cmd->cmnd = req->cmd;
+
return cmd;
}
@@ -1131,8 +1133,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
req->buffer = NULL;
}
- BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
- memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
cmd->cmd_len = req->cmd_len;
if (!req->data_len)
cmd->sc_data_direction = DMA_NONE;
@@ -1169,6 +1169,7 @@ int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
if (unlikely(!cmd))
return BLKPREP_DEFER;
+ memset(cmd->cmnd, 0, BLK_MAX_CDB);
return scsi_init_io(cmd, GFP_ATOMIC);
}
EXPORT_SYMBOL(scsi_setup_fs_cmnd);
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index ee8496aa033..257e097c39a 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -107,6 +107,8 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
cmd->jiffies_at_alloc = jiffies;
cmd->request = rq;
+ cmd->cmnd = rq->cmd;
+
rq->special = cmd;
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->cmd_flags |= REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 640333b1e75..329eb8780e7 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -744,7 +744,8 @@ static int wait_on_busy(unsigned long iobase, unsigned int loop) {
static int board_inquiry(unsigned int j) {
struct mscp *cpp;
dma_addr_t id_dma_addr;
- unsigned int time, limit = 0;
+ unsigned int limit = 0;
+ unsigned long time;
id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id,
sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL);
@@ -1392,7 +1393,8 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
}
static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
- unsigned int i, j, time, k, c, limit = 0;
+ unsigned int i, j, k, c, limit = 0;
+ unsigned long time;
int arg_done = FALSE;
struct scsi_cmnd *SCpnt;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index ea41f262645..a1ca9b7bf2d 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2271,7 +2271,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
}
if (up->port.flags & UPF_IOREMAP) {
- up->port.membase = ioremap(up->port.mapbase, size);
+ up->port.membase = ioremap_nocache(up->port.mapbase,
+ size);
if (!up->port.membase) {
release_mem_region(up->port.mapbase, size);
ret = -ENOMEM;
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index cd898704ba4..f279745e9fe 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -153,7 +153,7 @@ static int __init parse_options(struct early_serial8250_device *device,
(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
port->membase += port->mapbase & ~PAGE_MASK;
#else
- port->membase = ioremap(port->mapbase, 64);
+ port->membase = ioremap_nocache(port->mapbase, 64);
if (!port->membase) {
printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
__func__,
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 6e57382b913..53fa19cf2f0 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -86,7 +86,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
len = pci_resource_len(dev, bar);
if (!priv->remapped_bar[bar])
- priv->remapped_bar[bar] = ioremap(base, len);
+ priv->remapped_bar[bar] = ioremap_nocache(base, len);
if (!priv->remapped_bar[bar])
return -ENOMEM;
@@ -270,7 +270,7 @@ static int pci_plx9050_init(struct pci_dev *dev)
/*
* enable/disable interrupts
*/
- p = ioremap(pci_resource_start(dev, 0), 0x80);
+ p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
if (p == NULL)
return -ENOMEM;
writel(irq_config, p + 0x4c);
@@ -294,7 +294,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
/*
* disable interrupts
*/
- p = ioremap(pci_resource_start(dev, 0), 0x80);
+ p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
if (p != NULL) {
writel(0, p + 0x4c);
@@ -341,7 +341,8 @@ static int sbs_init(struct pci_dev *dev)
{
u8 __iomem *p;
- p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+ p = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
if (p == NULL)
return -ENOMEM;
@@ -365,7 +366,8 @@ static void __devexit sbs_exit(struct pci_dev *dev)
{
u8 __iomem *p;
- p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+ p = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
/* FIXME: What if resource_len < OCT_REG_CR_OFF */
if (p != NULL)
writeb(0, p + OCT_REG_CR_OFF);
@@ -419,7 +421,7 @@ static int pci_siig10x_init(struct pci_dev *dev)
break;
}
- p = ioremap(pci_resource_start(dev, 0), 0x80);
+ p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
if (p == NULL)
return -ENOMEM;
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
index 12c934a1f27..8871aaa3dba 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/serial/jsm/jsm.h
@@ -373,6 +373,7 @@ struct neo_uart_struct {
#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
#define PCI_DEVICE_NEO_2RJ45_PCI_NAME "Neo 2 - RJ45 Universal PCI"
#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
+#define PCIE_DEVICE_NEO_IBM_PCI_NAME "Neo 4 - PCI Express - IBM"
/*
* Our Global Variables.
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index 6767ee381cd..338cf8a08b4 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -82,7 +82,10 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* store the info for the board we've found */
brd->boardnum = adapter_count++;
brd->pci_dev = pdev;
- brd->maxports = 2;
+ if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
+ brd->maxports = 4;
+ else
+ brd->maxports = 2;
spin_lock_init(&brd->bd_lock);
spin_lock_init(&brd->bd_intr_lock);
@@ -208,6 +211,7 @@ static struct pci_device_id jsm_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 7a3625f52a0..efc971d9647 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -783,7 +783,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
}
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(tty);
+ spin_lock(&port->lock);
return psc_ops->raw_rx_rdy(port);
}
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index be0fe152891..145c0281495 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -392,7 +392,7 @@ static struct uart_ops sunhv_pops = {
static struct uart_driver sunhv_reg = {
.owner = THIS_MODULE,
- .driver_name = "serial",
+ .driver_name = "sunhv",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 543f93741e6..9ff5b38f3be 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -826,7 +826,7 @@ static struct uart_ops sunsab_pops = {
static struct uart_driver sunsab_reg = {
.owner = THIS_MODULE,
- .driver_name = "serial",
+ .driver_name = "sunsab",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 4e2302d43ab..03806a93520 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1173,7 +1173,7 @@ out:
static struct uart_driver sunsu_reg = {
.owner = THIS_MODULE,
- .driver_name = "serial",
+ .driver_name = "sunsu",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 90a20a152eb..7e9fa5ef0eb 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1023,7 +1023,7 @@ static struct uart_sunzilog_port *sunzilog_irq_chain;
static struct uart_driver sunzilog_reg = {
.owner = THIS_MODULE,
- .driver_name = "ttyS",
+ .driver_name = "sunzilog",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index a9ac1fdb309..7fea3cf4588 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -608,6 +608,7 @@ static void pump_transfers(unsigned long data)
u8 width;
u16 cr, dma_width, dma_config;
u32 tranf_success = 1;
+ u8 full_duplex = 0;
/* Get current state information */
message = drv_data->cur_msg;
@@ -658,6 +659,7 @@ static void pump_transfers(unsigned long data)
}
if (transfer->rx_buf != NULL) {
+ full_duplex = transfer->tx_buf != NULL;
drv_data->rx = transfer->rx_buf;
drv_data->rx_end = drv_data->rx + transfer->len;
dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n",
@@ -740,7 +742,8 @@ static void pump_transfers(unsigned long data)
* successful use different way to r/w according to
* drv_data->cur_chip->enable_dma
*/
- if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
+ if (!full_duplex && drv_data->cur_chip->enable_dma
+ && drv_data->len > 6) {
disable_dma(drv_data->dma_channel);
clear_dma_irqstat(drv_data->dma_channel);
@@ -828,7 +831,7 @@ static void pump_transfers(unsigned long data)
/* IO mode write then read */
dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
- if (drv_data->tx != NULL && drv_data->rx != NULL) {
+ if (full_duplex) {
/* full duplex mode */
BUG_ON((drv_data->tx_end - drv_data->tx) !=
(drv_data->rx_end - drv_data->rx));
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 34bfb7dd776..0885cc357a3 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -125,10 +125,10 @@ static int s3c24xx_spi_setupxfer(struct spi_device *spi,
/* is clk = pclk / (2 * (pre+1)), or is it
* clk = (pclk * 2) / ( pre + 1) */
- div = (div / 2) - 1;
+ div /= 2;
- if (div < 0)
- div = 1;
+ if (div > 0)
+ div -= 1;
if (div > 255)
div = 255;
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 516a6400db4..a419c42e880 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -17,6 +17,8 @@ obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
+obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
+
obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_PRINTER) += class/
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
index 86e64035edb..be0b8daac9c 100644
--- a/drivers/usb/atm/Kconfig
+++ b/drivers/usb/atm/Kconfig
@@ -19,7 +19,6 @@ if USB_ATM
config USB_SPEEDTOUCH
tristate "Speedtouch USB support"
- depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an SpeedTouch USB or SpeedTouch 330
@@ -32,7 +31,6 @@ config USB_SPEEDTOUCH
config USB_CXACRU
tristate "Conexant AccessRunner USB support"
- depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an ADSL USB modem based on the Conexant
@@ -45,7 +43,6 @@ config USB_CXACRU
config USB_UEAGLEATM
tristate "ADI 930 and eagle USB DSL modem"
- depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an ADSL USB modem based on the ADI 930
@@ -58,7 +55,6 @@ config USB_UEAGLEATM
config USB_XUSBATM
tristate "Other USB DSL modem support"
- depends on USB_ATM
help
Say Y here if you have a DSL USB modem not explicitly supported by
another USB DSL drivers. In order to use your modem you will need to
diff --git a/drivers/usb/c67x00/Makefile b/drivers/usb/c67x00/Makefile
new file mode 100644
index 00000000000..868bc41b598
--- /dev/null
+++ b/drivers/usb/c67x00/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for Cypress C67X00 USB Controller
+#
+
+ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
+
+obj-$(CONFIG_USB_C67X00_HCD) += c67x00.o
+
+c67x00-objs := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
new file mode 100644
index 00000000000..5633bc5c8bf
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-drv.c
@@ -0,0 +1,243 @@
+/*
+ * c67x00-drv.c: Cypress C67X00 USB Common infrastructure
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * This file implements the common infrastructure for using the c67x00.
+ * It is both the link between the platform configuration and subdrivers and
+ * the link between the common hardware parts and the subdrivers (e.g.
+ * interrupt handling).
+ *
+ * The c67x00 has 2 SIE's (serial interface engine) wich can be configured
+ * to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG).
+ *
+ * Depending on the platform configuration, the SIE's are created and
+ * the corresponding subdriver is initialized (c67x00_probe_sie).
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/usb/c67x00.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+static void c67x00_probe_sie(struct c67x00_sie *sie,
+ struct c67x00_device *dev, int sie_num)
+{
+ spin_lock_init(&sie->lock);
+ sie->dev = dev;
+ sie->sie_num = sie_num;
+ sie->mode = c67x00_sie_config(dev->pdata->sie_config, sie_num);
+
+ switch (sie->mode) {
+ case C67X00_SIE_HOST:
+ c67x00_hcd_probe(sie);
+ break;
+
+ case C67X00_SIE_UNUSED:
+ dev_info(sie_dev(sie),
+ "Not using SIE %d as requested\n", sie->sie_num);
+ break;
+
+ default:
+ dev_err(sie_dev(sie),
+ "Unsupported configuration: 0x%x for SIE %d\n",
+ sie->mode, sie->sie_num);
+ break;
+ }
+}
+
+static void c67x00_remove_sie(struct c67x00_sie *sie)
+{
+ switch (sie->mode) {
+ case C67X00_SIE_HOST:
+ c67x00_hcd_remove(sie);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static irqreturn_t c67x00_irq(int irq, void *__dev)
+{
+ struct c67x00_device *c67x00 = __dev;
+ struct c67x00_sie *sie;
+ u16 msg, int_status;
+ int i, count = 8;
+
+ int_status = c67x00_ll_hpi_status(c67x00);
+ if (!int_status)
+ return IRQ_NONE;
+
+ while (int_status != 0 && (count-- >= 0)) {
+ c67x00_ll_irq(c67x00, int_status);
+ for (i = 0; i < C67X00_SIES; i++) {
+ sie = &c67x00->sie[i];
+ msg = 0;
+ if (int_status & SIEMSG_FLG(i))
+ msg = c67x00_ll_fetch_siemsg(c67x00, i);
+ if (sie->irq)
+ sie->irq(sie, int_status, msg);
+ }
+ int_status = c67x00_ll_hpi_status(c67x00);
+ }
+
+ if (int_status)
+ dev_warn(&c67x00->pdev->dev, "Not all interrupts handled! "
+ "status = 0x%04x\n", int_status);
+
+ return IRQ_HANDLED;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __devinit c67x00_drv_probe(struct platform_device *pdev)
+{
+ struct c67x00_device *c67x00;
+ struct c67x00_platform_data *pdata;
+ struct resource *res, *res2;
+ int ret, i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ c67x00 = kzalloc(sizeof(*c67x00), GFP_KERNEL);
+ if (!c67x00)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ ret = -EBUSY;
+ goto request_mem_failed;
+ }
+ c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1);
+ if (!c67x00->hpi.base) {
+ dev_err(&pdev->dev, "Unable to map HPI registers\n");
+ ret = -EIO;
+ goto map_failed;
+ }
+
+ spin_lock_init(&c67x00->hpi.lock);
+ c67x00->hpi.regstep = pdata->hpi_regstep;
+ c67x00->pdata = pdev->dev.platform_data;
+ c67x00->pdev = pdev;
+
+ c67x00_ll_init(c67x00);
+ c67x00_ll_hpi_reg_init(c67x00);
+
+ ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto request_irq_failed;
+ }
+
+ ret = c67x00_ll_reset(c67x00);
+ if (ret) {
+ dev_err(&pdev->dev, "Device reset failed\n");
+ goto reset_failed;
+ }
+
+ for (i = 0; i < C67X00_SIES; i++)
+ c67x00_probe_sie(&c67x00->sie[i], c67x00, i);
+
+ platform_set_drvdata(pdev, c67x00);
+
+ return 0;
+
+ reset_failed:
+ free_irq(res2->start, c67x00);
+ request_irq_failed:
+ iounmap(c67x00->hpi.base);
+ map_failed:
+ release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+ kfree(c67x00);
+
+ return ret;
+}
+
+static int __devexit c67x00_drv_remove(struct platform_device *pdev)
+{
+ struct c67x00_device *c67x00 = platform_get_drvdata(pdev);
+ struct resource *res;
+ int i;
+
+ for (i = 0; i < C67X00_SIES; i++)
+ c67x00_remove_sie(&c67x00->sie[i]);
+
+ c67x00_ll_release(c67x00);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res)
+ free_irq(res->start, c67x00);
+
+ iounmap(c67x00->hpi.base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(c67x00);
+
+ return 0;
+}
+
+static struct platform_driver c67x00_driver = {
+ .probe = c67x00_drv_probe,
+ .remove = __devexit_p(c67x00_drv_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "c67x00",
+ },
+};
+MODULE_ALIAS("platform:c67x00");
+
+static int __init c67x00_init(void)
+{
+ return platform_driver_register(&c67x00_driver);
+}
+
+static void __exit c67x00_exit(void)
+{
+ platform_driver_unregister(&c67x00_driver);
+}
+
+module_init(c67x00_init);
+module_exit(c67x00_exit);
+
+MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
+MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c
new file mode 100644
index 00000000000..a22b887f4e9
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-hcd.c
@@ -0,0 +1,412 @@
+/*
+ * c67x00-hcd.c: Cypress C67X00 USB Host Controller Driver
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+/* --------------------------------------------------------------------------
+ * Root Hub Support
+ */
+
+static __u8 c67x00_hub_des[] = {
+ 0x09, /* __u8 bLength; */
+ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
+ 0x02, /* __u8 bNbrPorts; */
+ 0x00, /* __u16 wHubCharacteristics; */
+ 0x00, /* (per-port OC, no power switching) */
+ 0x32, /* __u8 bPwrOn2pwrGood; 2ms */
+ 0x00, /* __u8 bHubContrCurrent; 0 mA */
+ 0x00, /* __u8 DeviceRemovable; ** 7 Ports max ** */
+ 0xff, /* __u8 PortPwrCtrlMask; ** 7 ports max ** */
+};
+
+static void c67x00_hub_reset_host_port(struct c67x00_sie *sie, int port)
+{
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ unsigned long flags;
+
+ c67x00_ll_husb_reset(sie, port);
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+ c67x00_ll_husb_reset_port(sie, port);
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ c67x00_ll_set_husb_eot(sie->dev, DEFAULT_EOT);
+}
+
+static int c67x00_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ struct c67x00_sie *sie = c67x00->sie;
+ u16 status;
+ int i;
+
+ *buf = 0;
+ status = c67x00_ll_usb_get_status(sie);
+ for (i = 0; i < C67X00_PORTS; i++)
+ if (status & PORT_CONNECT_CHANGE(i))
+ *buf |= (1 << i);
+
+ /* bit 0 denotes hub change, b1..n port change */
+ *buf <<= 1;
+
+ return !!*buf;
+}
+
+static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ struct c67x00_sie *sie = c67x00->sie;
+ u16 status, usb_status;
+ int len = 0;
+ unsigned int port = wIndex-1;
+ u16 wPortChange, wPortStatus;
+
+ switch (typeReq) {
+
+ case GetHubStatus:
+ *(__le32 *) buf = cpu_to_le32(0);
+ len = 4; /* hub power */
+ break;
+
+ case GetPortStatus:
+ if (wIndex > C67X00_PORTS)
+ return -EPIPE;
+
+ status = c67x00_ll_usb_get_status(sie);
+ usb_status = c67x00_ll_get_usb_ctl(sie);
+
+ wPortChange = 0;
+ if (status & PORT_CONNECT_CHANGE(port))
+ wPortChange |= USB_PORT_STAT_C_CONNECTION;
+
+ wPortStatus = USB_PORT_STAT_POWER;
+ if (!(status & PORT_SE0_STATUS(port)))
+ wPortStatus |= USB_PORT_STAT_CONNECTION;
+ if (usb_status & LOW_SPEED_PORT(port)) {
+ wPortStatus |= USB_PORT_STAT_LOW_SPEED;
+ c67x00->low_speed_ports |= (1 << port);
+ } else
+ c67x00->low_speed_ports &= ~(1 << port);
+
+ if (usb_status & SOF_EOP_EN(port))
+ wPortStatus |= USB_PORT_STAT_ENABLE;
+
+ *(__le16 *) buf = cpu_to_le16(wPortStatus);
+ *(__le16 *) (buf + 2) = cpu_to_le16(wPortChange);
+ len = 4;
+ break;
+
+ case SetHubFeature: /* We don't implement these */
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ len = 0;
+ break;
+
+ default:
+ return -EPIPE;
+ }
+ break;
+
+ case SetPortFeature:
+ if (wIndex > C67X00_PORTS)
+ return -EPIPE;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "SetPortFeature %d (SUSPEND)\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_RESET:
+ c67x00_hub_reset_host_port(sie, port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ /* Power always enabled */
+ len = 0;
+ break;
+
+ default:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "%s: SetPortFeature %d (0x%04x) Error!\n",
+ __func__, port, wValue);
+ return -EPIPE;
+ }
+ break;
+
+ case ClearPortFeature:
+ if (wIndex > C67X00_PORTS)
+ return -EPIPE;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ /* Reset the port so that the c67x00 also notices the
+ * disconnect */
+ c67x00_hub_reset_host_port(sie, port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_ENABLE:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): C_ENABLE\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): SUSPEND\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_SUSPEND:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): C_SUSPEND\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): POWER\n", port);
+ return -EPIPE;
+
+ case USB_PORT_FEAT_C_CONNECTION:
+ c67x00_ll_usb_clear_status(sie,
+ PORT_CONNECT_CHANGE(port));
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): OVER_CURRENT\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_RESET:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): C_RESET\n", port);
+ len = 0;
+ break;
+
+ default:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "%s: ClearPortFeature %d (0x%04x) Error!\n",
+ __func__, port, wValue);
+ return -EPIPE;
+ }
+ break;
+
+ case GetHubDescriptor:
+ len = min_t(unsigned int, sizeof(c67x00_hub_des), wLength);
+ memcpy(buf, c67x00_hub_des, len);
+ break;
+
+ default:
+ dev_dbg(c67x00_hcd_dev(c67x00), "%s: unknown\n", __func__);
+ return -EPIPE;
+ }
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Main part of host controller driver
+ */
+
+/**
+ * c67x00_hcd_irq
+ *
+ * This function is called from the interrupt handler in c67x00-drv.c
+ */
+static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
+{
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
+
+ /* Handle sie message flags */
+ if (msg) {
+ if (msg & HUSB_TDListDone)
+ c67x00_sched_kick(c67x00);
+ else
+ dev_warn(c67x00_hcd_dev(c67x00),
+ "Unknown SIE msg flag(s): 0x%04x\n", msg);
+ }
+
+ if (unlikely(hcd->state == HC_STATE_HALT))
+ return;
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+ return;
+
+ /* Handle Start of frame events */
+ if (int_status & SOFEOP_FLG(sie->sie_num)) {
+ c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
+ c67x00_sched_kick(c67x00);
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+ }
+}
+
+/**
+ * c67x00_hcd_start: Host controller start hook
+ */
+static int c67x00_hcd_start(struct usb_hcd *hcd)
+{
+ hcd->uses_new_polling = 1;
+ hcd->state = HC_STATE_RUNNING;
+ hcd->poll_rh = 1;
+
+ return 0;
+}
+
+/**
+ * c67x00_hcd_stop: Host controller stop hook
+ */
+static void c67x00_hcd_stop(struct usb_hcd *hcd)
+{
+ /* Nothing to do */
+}
+
+static int c67x00_hcd_get_frame(struct usb_hcd *hcd)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ u16 temp_val;
+
+ dev_dbg(c67x00_hcd_dev(c67x00), "%s\n", __func__);
+ temp_val = c67x00_ll_husb_get_frame(c67x00->sie);
+ temp_val &= HOST_FRAME_MASK;
+ return temp_val ? (temp_val - 1) : HOST_FRAME_MASK;
+}
+
+static struct hc_driver c67x00_hc_driver = {
+ .description = "c67x00-hcd",
+ .product_desc = "Cypress C67X00 Host Controller",
+ .hcd_priv_size = sizeof(struct c67x00_hcd),
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = c67x00_hcd_start,
+ .stop = c67x00_hcd_stop,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = c67x00_urb_enqueue,
+ .urb_dequeue = c67x00_urb_dequeue,
+ .endpoint_disable = c67x00_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = c67x00_hcd_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = c67x00_hub_status_data,
+ .hub_control = c67x00_hub_control,
+};
+
+/* ---------------------------------------------------------------------
+ * Setup/Teardown routines
+ */
+
+int c67x00_hcd_probe(struct c67x00_sie *sie)
+{
+ struct c67x00_hcd *c67x00;
+ struct usb_hcd *hcd;
+ unsigned long flags;
+ int retval;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ hcd = usb_create_hcd(&c67x00_hc_driver, sie_dev(sie), "c67x00_sie");
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err0;
+ }
+ c67x00 = hcd_to_c67x00_hcd(hcd);
+
+ spin_lock_init(&c67x00->lock);
+ c67x00->sie = sie;
+
+ INIT_LIST_HEAD(&c67x00->list[PIPE_ISOCHRONOUS]);
+ INIT_LIST_HEAD(&c67x00->list[PIPE_INTERRUPT]);
+ INIT_LIST_HEAD(&c67x00->list[PIPE_CONTROL]);
+ INIT_LIST_HEAD(&c67x00->list[PIPE_BULK]);
+ c67x00->urb_count = 0;
+ INIT_LIST_HEAD(&c67x00->td_list);
+ c67x00->td_base_addr = CY_HCD_BUF_ADDR + SIE_TD_OFFSET(sie->sie_num);
+ c67x00->buf_base_addr = CY_HCD_BUF_ADDR + SIE_BUF_OFFSET(sie->sie_num);
+ c67x00->max_frame_bw = MAX_FRAME_BW_STD;
+
+ c67x00_ll_husb_init_host_port(sie);
+
+ init_completion(&c67x00->endpoint_disable);
+ retval = c67x00_sched_start_scheduler(c67x00);
+ if (retval)
+ goto err1;
+
+ retval = usb_add_hcd(hcd, 0, 0);
+ if (retval) {
+ dev_dbg(sie_dev(sie), "%s: usb_add_hcd returned %d\n",
+ __func__, retval);
+ goto err2;
+ }
+
+ spin_lock_irqsave(&sie->lock, flags);
+ sie->private_data = c67x00;
+ sie->irq = c67x00_hcd_irq;
+ spin_unlock_irqrestore(&sie->lock, flags);
+
+ return retval;
+
+ err2:
+ c67x00_sched_stop_scheduler(c67x00);
+ err1:
+ usb_put_hcd(hcd);
+ err0:
+ return retval;
+}
+
+/* may be called with controller, bus, and devices active */
+void c67x00_hcd_remove(struct c67x00_sie *sie)
+{
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
+
+ c67x00_sched_stop_scheduler(c67x00);
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+}
diff --git a/drivers/usb/c67x00/c67x00-hcd.h b/drivers/usb/c67x00/c67x00-hcd.h
new file mode 100644
index 00000000000..e8c6d94b251
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-hcd.h
@@ -0,0 +1,133 @@
+/*
+ * c67x00-hcd.h: Cypress C67X00 USB HCD
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#ifndef _USB_C67X00_HCD_H
+#define _USB_C67X00_HCD_H
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include "../core/hcd.h"
+#include "c67x00.h"
+
+/*
+ * The following parameters depend on the CPU speed, bus speed, ...
+ * These can be tuned for specific use cases, e.g. if isochronous transfers
+ * are very important, bandwith can be sacrificed to guarantee that the
+ * 1ms deadline will be met.
+ * If bulk transfers are important, the MAX_FRAME_BW can be increased,
+ * but some (or many) isochronous deadlines might not be met.
+ *
+ * The values are specified in bittime.
+ */
+
+/*
+ * The current implementation switches between _STD (default) and _ISO (when
+ * isochronous transfers are scheduled), in order to optimize the throughput
+ * in normal cicrumstances, but also provide good isochronous behaviour.
+ *
+ * Bandwidth is described in bit time so with a 12MHz USB clock and 1ms
+ * frames; there are 12000 bit times per frame.
+ */
+
+#define TOTAL_FRAME_BW 12000
+#define DEFAULT_EOT 2250
+
+#define MAX_FRAME_BW_STD (TOTAL_FRAME_BW - DEFAULT_EOT)
+#define MAX_FRAME_BW_ISO 2400
+
+/*
+ * Periodic transfers may only use 90% of the full frame, but as
+ * we currently don't even use 90% of the full frame, we may
+ * use the full usable time for periodic transfers.
+ */
+#define MAX_PERIODIC_BW(full_bw) full_bw
+
+/* -------------------------------------------------------------------------- */
+
+struct c67x00_hcd {
+ spinlock_t lock;
+ struct c67x00_sie *sie;
+ unsigned int low_speed_ports; /* bitmask of low speed ports */
+ unsigned int urb_count;
+ unsigned int urb_iso_count;
+
+ struct list_head list[4]; /* iso, int, ctrl, bulk */
+#if PIPE_BULK != 3
+#error "Sanity check failed, this code presumes PIPE_... to range from 0 to 3"
+#endif
+
+ /* USB bandwidth allocated to td_list */
+ int bandwidth_allocated;
+ /* USB bandwidth allocated for isoc/int transfer */
+ int periodic_bw_allocated;
+ struct list_head td_list;
+ int max_frame_bw;
+
+ u16 td_base_addr;
+ u16 buf_base_addr;
+ u16 next_td_addr;
+ u16 next_buf_addr;
+
+ struct tasklet_struct tasklet;
+
+ struct completion endpoint_disable;
+
+ u16 current_frame;
+ u16 last_frame;
+};
+
+static inline struct c67x00_hcd *hcd_to_c67x00_hcd(struct usb_hcd *hcd)
+{
+ return (struct c67x00_hcd *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *c67x00_hcd_to_hcd(struct c67x00_hcd *c67x00)
+{
+ return container_of((void *)c67x00, struct usb_hcd, hcd_priv);
+}
+
+/* ---------------------------------------------------------------------
+ * Functions used by c67x00-drv
+ */
+
+int c67x00_hcd_probe(struct c67x00_sie *sie);
+void c67x00_hcd_remove(struct c67x00_sie *sie);
+
+/* ---------------------------------------------------------------------
+ * Transfer Descriptor scheduling functions
+ */
+int c67x00_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
+int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+void c67x00_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep);
+
+void c67x00_hcd_msg_received(struct c67x00_sie *sie, u16 msg);
+void c67x00_sched_kick(struct c67x00_hcd *c67x00);
+int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00);
+void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00);
+
+#define c67x00_hcd_dev(x) (c67x00_hcd_to_hcd(x)->self.controller)
+
+#endif /* _USB_C67X00_HCD_H */
diff --git a/drivers/usb/c67x00/c67x00-ll-hpi.c b/drivers/usb/c67x00/c67x00-ll-hpi.c
new file mode 100644
index 00000000000..f3430b372f0
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-ll-hpi.c
@@ -0,0 +1,480 @@
+/*
+ * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <asm/byteorder.h>
+#include <linux/io.h>
+#include <linux/usb/c67x00.h>
+#include "c67x00.h"
+
+#define COMM_REGS 14
+
+struct c67x00_lcp_int_data {
+ u16 regs[COMM_REGS];
+};
+
+/* -------------------------------------------------------------------------- */
+/* Interface definitions */
+
+#define COMM_ACK 0x0FED
+#define COMM_NAK 0xDEAD
+
+#define COMM_RESET 0xFA50
+#define COMM_EXEC_INT 0xCE01
+#define COMM_INT_NUM 0x01C2
+
+/* Registers 0 to COMM_REGS-1 */
+#define COMM_R(x) (0x01C4 + 2 * (x))
+
+#define HUSB_SIE_pCurrentTDPtr(x) ((x) ? 0x01B2 : 0x01B0)
+#define HUSB_SIE_pTDListDone_Sem(x) ((x) ? 0x01B8 : 0x01B6)
+#define HUSB_pEOT 0x01B4
+
+/* Software interrupts */
+/* 114, 115: */
+#define HUSB_SIE_INIT_INT(x) ((x) ? 0x0073 : 0x0072)
+#define HUSB_RESET_INT 0x0074
+
+#define SUSB_INIT_INT 0x0071
+#define SUSB_INIT_INT_LOC (SUSB_INIT_INT * 2)
+
+/* -----------------------------------------------------------------------
+ * HPI implementation
+ *
+ * The c67x00 chip also support control via SPI or HSS serial
+ * interfaces. However, this driver assumes that register access can
+ * be performed from IRQ context. While this is a safe assuption with
+ * the HPI interface, it is not true for the serial interfaces.
+ */
+
+/* HPI registers */
+#define HPI_DATA 0
+#define HPI_MAILBOX 1
+#define HPI_ADDR 2
+#define HPI_STATUS 3
+
+static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)
+{
+ return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)
+{
+ __raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg)
+{
+ hpi_write_reg(dev, HPI_ADDR, reg);
+ return hpi_read_reg(dev, HPI_DATA);
+}
+
+static u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_word_nolock(dev, reg);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value)
+{
+ hpi_write_reg(dev, HPI_ADDR, reg);
+ hpi_write_reg(dev, HPI_DATA, value);
+}
+
+static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ hpi_write_word_nolock(dev, reg, value);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
+ u16 *data, u16 count)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+
+ hpi_write_reg(dev, HPI_ADDR, addr);
+ for (i = 0; i < count; i++)
+ hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++));
+
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
+ u16 *data, u16 count)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ hpi_write_reg(dev, HPI_ADDR, addr);
+ for (i = 0; i < count; i++)
+ *data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA));
+
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_word_nolock(dev, reg);
+ hpi_write_word_nolock(dev, reg, value | mask);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_word_nolock(dev, reg);
+ hpi_write_word_nolock(dev, reg, value & ~mask);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static u16 hpi_recv_mbox(struct c67x00_device *dev)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_reg(dev, HPI_MAILBOX);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ hpi_write_reg(dev, HPI_MAILBOX, value);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_reg(dev, HPI_STATUS);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
+{
+ int i;
+
+ hpi_recv_mbox(dev);
+ c67x00_ll_hpi_status(dev);
+ hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
+
+ for (i = 0; i < C67X00_SIES; i++) {
+ hpi_write_word(dev, SIEMSG_REG(i), 0);
+ hpi_read_word(dev, SIEMSG_REG(i));
+ }
+}
+
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie)
+{
+ hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+ SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
+{
+ hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+ SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+/* Transactions */
+
+static inline u16 ll_recv_msg(struct c67x00_device *dev)
+{
+ u16 res;
+
+ res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
+ WARN_ON(!res);
+
+ return (res == 0) ? -EIO : 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* General functions */
+
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num)
+{
+ u16 val;
+
+ val = hpi_read_word(dev, SIEMSG_REG(sie_num));
+ /* clear register to allow next message */
+ hpi_write_word(dev, SIEMSG_REG(sie_num), 0);
+
+ return val;
+}
+
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
+}
+
+/**
+ * c67x00_ll_usb_clear_status - clear the USB status bits
+ */
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
+{
+ hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
+}
+
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
+ struct c67x00_lcp_int_data *data)
+{
+ int i, rc;
+
+ mutex_lock(&dev->hpi.lcp.mutex);
+ hpi_write_word(dev, COMM_INT_NUM, nr);
+ for (i = 0; i < COMM_REGS; i++)
+ hpi_write_word(dev, COMM_R(i), data->regs[i]);
+ hpi_send_mbox(dev, COMM_EXEC_INT);
+ rc = ll_recv_msg(dev);
+ mutex_unlock(&dev->hpi.lcp.mutex);
+
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Host specific functions */
+
+void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value)
+{
+ mutex_lock(&dev->hpi.lcp.mutex);
+ hpi_write_word(dev, HUSB_pEOT, value);
+ mutex_unlock(&dev->hpi.lcp.mutex);
+}
+
+static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie)
+{
+ struct c67x00_device *dev = sie->dev;
+ struct c67x00_lcp_int_data data;
+ int rc;
+
+ rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data);
+ BUG_ON(rc); /* No return path for error code; crash spectacularly */
+}
+
+void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port)
+{
+ struct c67x00_device *dev = sie->dev;
+ struct c67x00_lcp_int_data data;
+ int rc;
+
+ data.regs[0] = 50; /* Reset USB port for 50ms */
+ data.regs[1] = port | (sie->sie_num << 1);
+ rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data);
+ BUG_ON(rc); /* No return path for error code; crash spectacularly */
+}
+
+void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr)
+{
+ hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr);
+}
+
+u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num));
+}
+
+u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num));
+}
+
+void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie)
+{
+ /* Set port into host mode */
+ hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE);
+ c67x00_ll_husb_sie_init(sie);
+ /* Clear interrupts */
+ c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK);
+ /* Check */
+ if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
+ dev_warn(sie_dev(sie),
+ "SIE %d not set to host mode\n", sie->sie_num);
+}
+
+void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port)
+{
+ /* Clear connect change */
+ c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port));
+
+ /* Enable interrupts */
+ hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+ SOFEOP_TO_CPU_EN(sie->sie_num));
+ hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num),
+ SOF_EOP_IRQ_EN | DONE_IRQ_EN);
+
+ /* Enable pull down transistors */
+ hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port));
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
+{
+ if ((int_status & MBX_OUT_FLG) == 0)
+ return;
+
+ dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
+ complete(&dev->hpi.lcp.msg_received);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int c67x00_ll_reset(struct c67x00_device *dev)
+{
+ int rc;
+
+ mutex_lock(&dev->hpi.lcp.mutex);
+ hpi_send_mbox(dev, COMM_RESET);
+ rc = ll_recv_msg(dev);
+ mutex_unlock(&dev->hpi.lcp.mutex);
+
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_ll_write_mem_le16 - write into c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len)
+{
+ u8 *buf = data;
+
+ /* Sanity check */
+ if (addr + len > 0xffff) {
+ dev_err(&dev->pdev->dev,
+ "Trying to write beyond writable region!\n");
+ return;
+ }
+
+ if (addr & 0x01) {
+ /* unaligned access */
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr - 1);
+ tmp = (tmp & 0x00ff) | (*buf++ << 8);
+ hpi_write_word(dev, addr - 1, tmp);
+ addr++;
+ len--;
+ }
+
+ hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2);
+ buf += len & ~0x01;
+ addr += len & ~0x01;
+ len &= 0x01;
+
+ if (len) {
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr);
+ tmp = (tmp & 0xff00) | *buf;
+ hpi_write_word(dev, addr, tmp);
+ }
+}
+
+/**
+ * c67x00_ll_read_mem_le16 - read from c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len)
+{
+ u8 *buf = data;
+
+ if (addr & 0x01) {
+ /* unaligned access */
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr - 1);
+ *buf++ = (tmp >> 8) & 0x00ff;
+ addr++;
+ len--;
+ }
+
+ hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2);
+ buf += len & ~0x01;
+ addr += len & ~0x01;
+ len &= 0x01;
+
+ if (len) {
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr);
+ *buf = tmp & 0x00ff;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_init(struct c67x00_device *dev)
+{
+ mutex_init(&dev->hpi.lcp.mutex);
+ init_completion(&dev->hpi.lcp.msg_received);
+}
+
+void c67x00_ll_release(struct c67x00_device *dev)
+{
+}
diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c
new file mode 100644
index 00000000000..85dfe296566
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-sched.c
@@ -0,0 +1,1170 @@
+/*
+ * c67x00-sched.c: Cypress C67X00 USB Host Controller Driver - TD scheduling
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/kthread.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+/*
+ * These are the stages for a control urb, they are kept
+ * in both urb->interval and td->privdata.
+ */
+#define SETUP_STAGE 0
+#define DATA_STAGE 1
+#define STATUS_STAGE 2
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * struct c67x00_ep_data: Host endpoint data structure
+ */
+struct c67x00_ep_data {
+ struct list_head queue;
+ struct list_head node;
+ struct usb_host_endpoint *hep;
+ struct usb_device *dev;
+ u16 next_frame; /* For int/isoc transactions */
+};
+
+/**
+ * struct c67x00_td
+ *
+ * Hardware parts are little endiannes, SW in CPU endianess.
+ */
+struct c67x00_td {
+ /* HW specific part */
+ __le16 ly_base_addr; /* Bytes 0-1 */
+ __le16 port_length; /* Bytes 2-3 */
+ u8 pid_ep; /* Byte 4 */
+ u8 dev_addr; /* Byte 5 */
+ u8 ctrl_reg; /* Byte 6 */
+ u8 status; /* Byte 7 */
+ u8 retry_cnt; /* Byte 8 */
+#define TT_OFFSET 2
+#define TT_CONTROL 0
+#define TT_ISOCHRONOUS 1
+#define TT_BULK 2
+#define TT_INTERRUPT 3
+ u8 residue; /* Byte 9 */
+ __le16 next_td_addr; /* Bytes 10-11 */
+ /* SW part */
+ struct list_head td_list;
+ u16 td_addr;
+ void *data;
+ struct urb *urb;
+ unsigned long privdata;
+
+ /* These are needed for handling the toggle bits:
+ * an urb can be dequeued while a td is in progress
+ * after checking the td, the toggle bit might need to
+ * be fixed */
+ struct c67x00_ep_data *ep_data;
+ unsigned int pipe;
+};
+
+struct c67x00_urb_priv {
+ struct list_head hep_node;
+ struct urb *urb;
+ int port;
+ int cnt; /* packet number for isoc */
+ int status;
+ struct c67x00_ep_data *ep_data;
+};
+
+#define td_udev(td) ((td)->ep_data->dev)
+
+#define CY_TD_SIZE 12
+
+#define TD_PIDEP_OFFSET 0x04
+#define TD_PIDEPMASK_PID 0xF0
+#define TD_PIDEPMASK_EP 0x0F
+#define TD_PORTLENMASK_DL 0x02FF
+#define TD_PORTLENMASK_PN 0xC000
+
+#define TD_STATUS_OFFSET 0x07
+#define TD_STATUSMASK_ACK 0x01
+#define TD_STATUSMASK_ERR 0x02
+#define TD_STATUSMASK_TMOUT 0x04
+#define TD_STATUSMASK_SEQ 0x08
+#define TD_STATUSMASK_SETUP 0x10
+#define TD_STATUSMASK_OVF 0x20
+#define TD_STATUSMASK_NAK 0x40
+#define TD_STATUSMASK_STALL 0x80
+
+#define TD_ERROR_MASK (TD_STATUSMASK_ERR | TD_STATUSMASK_TMOUT | \
+ TD_STATUSMASK_STALL)
+
+#define TD_RETRYCNT_OFFSET 0x08
+#define TD_RETRYCNTMASK_ACT_FLG 0x10
+#define TD_RETRYCNTMASK_TX_TYPE 0x0C
+#define TD_RETRYCNTMASK_RTY_CNT 0x03
+
+#define TD_RESIDUE_OVERFLOW 0x80
+
+#define TD_PID_IN 0x90
+
+/* Residue: signed 8bits, neg -> OVERFLOW, pos -> UNDERFLOW */
+#define td_residue(td) ((__s8)(td->residue))
+#define td_ly_base_addr(td) (__le16_to_cpu((td)->ly_base_addr))
+#define td_port_length(td) (__le16_to_cpu((td)->port_length))
+#define td_next_td_addr(td) (__le16_to_cpu((td)->next_td_addr))
+
+#define td_active(td) ((td)->retry_cnt & TD_RETRYCNTMASK_ACT_FLG)
+#define td_length(td) (td_port_length(td) & TD_PORTLENMASK_DL)
+
+#define td_sequence_ok(td) (!td->status || \
+ (!(td->status & TD_STATUSMASK_SEQ) == \
+ !(td->ctrl_reg & SEQ_SEL)))
+
+#define td_acked(td) (!td->status || \
+ (td->status & TD_STATUSMASK_ACK))
+#define td_actual_bytes(td) (td_length(td) - td_residue(td))
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef DEBUG
+
+/**
+ * dbg_td - Dump the contents of the TD
+ */
+static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg)
+{
+ struct device *dev = c67x00_hcd_dev(c67x00);
+
+ dev_dbg(dev, "### %s at 0x%04x\n", msg, td->td_addr);
+ dev_dbg(dev, "urb: 0x%p\n", td->urb);
+ dev_dbg(dev, "endpoint: %4d\n", usb_pipeendpoint(td->pipe));
+ dev_dbg(dev, "pipeout: %4d\n", usb_pipeout(td->pipe));
+ dev_dbg(dev, "ly_base_addr: 0x%04x\n", td_ly_base_addr(td));
+ dev_dbg(dev, "port_length: 0x%04x\n", td_port_length(td));
+ dev_dbg(dev, "pid_ep: 0x%02x\n", td->pid_ep);
+ dev_dbg(dev, "dev_addr: 0x%02x\n", td->dev_addr);
+ dev_dbg(dev, "ctrl_reg: 0x%02x\n", td->ctrl_reg);
+ dev_dbg(dev, "status: 0x%02x\n", td->status);
+ dev_dbg(dev, "retry_cnt: 0x%02x\n", td->retry_cnt);
+ dev_dbg(dev, "residue: 0x%02x\n", td->residue);
+ dev_dbg(dev, "next_td_addr: 0x%04x\n", td_next_td_addr(td));
+ dev_dbg(dev, "data:");
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1,
+ td->data, td_length(td), 1);
+}
+#else /* DEBUG */
+
+static inline void
+dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) { }
+
+#endif /* DEBUG */
+
+/* -------------------------------------------------------------------------- */
+/* Helper functions */
+
+static inline u16 c67x00_get_current_frame_number(struct c67x00_hcd *c67x00)
+{
+ return c67x00_ll_husb_get_frame(c67x00->sie) & HOST_FRAME_MASK;
+}
+
+/**
+ * frame_add
+ * Software wraparound for framenumbers.
+ */
+static inline u16 frame_add(u16 a, u16 b)
+{
+ return (a + b) & HOST_FRAME_MASK;
+}
+
+/**
+ * frame_after - is frame a after frame b
+ */
+static inline int frame_after(u16 a, u16 b)
+{
+ return ((HOST_FRAME_MASK + a - b) & HOST_FRAME_MASK) <
+ (HOST_FRAME_MASK / 2);
+}
+
+/**
+ * frame_after_eq - is frame a after or equal to frame b
+ */
+static inline int frame_after_eq(u16 a, u16 b)
+{
+ return ((HOST_FRAME_MASK + 1 + a - b) & HOST_FRAME_MASK) <
+ (HOST_FRAME_MASK / 2);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_release_urb - remove link from all tds to this urb
+ * Disconnects the urb from it's tds, so that it can be given back.
+ * pre: urb->hcpriv != NULL
+ */
+static void c67x00_release_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct c67x00_td *td;
+ struct c67x00_urb_priv *urbp;
+
+ BUG_ON(!urb);
+
+ c67x00->urb_count--;
+
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ c67x00->urb_iso_count--;
+ if (c67x00->urb_iso_count == 0)
+ c67x00->max_frame_bw = MAX_FRAME_BW_STD;
+ }
+
+ /* TODO this might be not so efficient when we've got many urbs!
+ * Alternatives:
+ * * only clear when needed
+ * * keep a list of tds with each urbp
+ */
+ list_for_each_entry(td, &c67x00->td_list, td_list)
+ if (urb == td->urb)
+ td->urb = NULL;
+
+ urbp = urb->hcpriv;
+ urb->hcpriv = NULL;
+ list_del(&urbp->hep_node);
+ kfree(urbp);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct c67x00_ep_data *
+c67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct usb_host_endpoint *hep = urb->ep;
+ struct c67x00_ep_data *ep_data;
+ int type;
+
+ c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
+
+ /* Check if endpoint already has a c67x00_ep_data struct allocated */
+ if (hep->hcpriv) {
+ ep_data = hep->hcpriv;
+ if (frame_after(c67x00->current_frame, ep_data->next_frame))
+ ep_data->next_frame =
+ frame_add(c67x00->current_frame, 1);
+ return hep->hcpriv;
+ }
+
+ /* Allocate and initialize a new c67x00 endpoint data structure */
+ ep_data = kzalloc(sizeof(*ep_data), GFP_ATOMIC);
+ if (!ep_data)
+ return NULL;
+
+ INIT_LIST_HEAD(&ep_data->queue);
+ INIT_LIST_HEAD(&ep_data->node);
+ ep_data->hep = hep;
+
+ /* hold a reference to udev as long as this endpoint lives,
+ * this is needed to possibly fix the data toggle */
+ ep_data->dev = usb_get_dev(urb->dev);
+ hep->hcpriv = ep_data;
+
+ /* For ISOC and INT endpoints, start ASAP: */
+ ep_data->next_frame = frame_add(c67x00->current_frame, 1);
+
+ /* Add the endpoint data to one of the pipe lists; must be added
+ in order of endpoint address */
+ type = usb_pipetype(urb->pipe);
+ if (list_empty(&ep_data->node)) {
+ list_add(&ep_data->node, &c67x00->list[type]);
+ } else {
+ struct c67x00_ep_data *prev;
+
+ list_for_each_entry(prev, &c67x00->list[type], node) {
+ if (prev->hep->desc.bEndpointAddress >
+ hep->desc.bEndpointAddress) {
+ list_add(&ep_data->node, prev->node.prev);
+ break;
+ }
+ }
+ }
+
+ return ep_data;
+}
+
+static int c67x00_ep_data_free(struct usb_host_endpoint *hep)
+{
+ struct c67x00_ep_data *ep_data = hep->hcpriv;
+
+ if (!ep_data)
+ return 0;
+
+ if (!list_empty(&ep_data->queue))
+ return -EBUSY;
+
+ usb_put_dev(ep_data->dev);
+ list_del(&ep_data->queue);
+ list_del(&ep_data->node);
+
+ kfree(ep_data);
+ hep->hcpriv = NULL;
+
+ return 0;
+}
+
+void c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ unsigned long flags;
+
+ if (!list_empty(&ep->urb_list))
+ dev_warn(c67x00_hcd_dev(c67x00), "error: urb list not empty\n");
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+
+ /* loop waiting for all transfers in the endpoint queue to complete */
+ while (c67x00_ep_data_free(ep)) {
+ /* Drop the lock so we can sleep waiting for the hardware */
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ /* it could happen that we reinitialize this completion, while
+ * somebody was waiting for that completion. The timeout and
+ * while loop handle such cases, but this might be improved */
+ INIT_COMPLETION(c67x00->endpoint_disable);
+ c67x00_sched_kick(c67x00);
+ wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ);
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+ }
+
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline int get_root_port(struct usb_device *dev)
+{
+ while (dev->parent->parent)
+ dev = dev->parent;
+ return dev->portnum;
+}
+
+int c67x00_urb_enqueue(struct usb_hcd *hcd,
+ struct urb *urb, gfp_t mem_flags)
+{
+ int ret;
+ unsigned long flags;
+ struct c67x00_urb_priv *urbp;
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ int port = get_root_port(urb->dev)-1;
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+
+ /* Make sure host controller is running */
+ if (!HC_IS_RUNNING(hcd->state)) {
+ ret = -ENODEV;
+ goto err_not_linked;
+ }
+
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto err_not_linked;
+
+ /* Allocate and initialize urb private data */
+ urbp = kzalloc(sizeof(*urbp), mem_flags);
+ if (!urbp) {
+ ret = -ENOMEM;
+ goto err_urbp;
+ }
+
+ INIT_LIST_HEAD(&urbp->hep_node);
+ urbp->urb = urb;
+ urbp->port = port;
+
+ urbp->ep_data = c67x00_ep_data_alloc(c67x00, urb);
+
+ if (!urbp->ep_data) {
+ ret = -ENOMEM;
+ goto err_epdata;
+ }
+
+ /* TODO claim bandwidth with usb_claim_bandwidth?
+ * also release it somewhere! */
+
+ urb->hcpriv = urbp;
+
+ urb->actual_length = 0; /* Nothing received/transmitted yet */
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ urb->interval = SETUP_STAGE;
+ break;
+ case PIPE_INTERRUPT:
+ break;
+ case PIPE_BULK:
+ break;
+ case PIPE_ISOCHRONOUS:
+ if (c67x00->urb_iso_count == 0)
+ c67x00->max_frame_bw = MAX_FRAME_BW_ISO;
+ c67x00->urb_iso_count++;
+ /* Assume always URB_ISO_ASAP, FIXME */
+ if (list_empty(&urbp->ep_data->queue))
+ urb->start_frame = urbp->ep_data->next_frame;
+ else {
+ /* Go right after the last one */
+ struct urb *last_urb;
+
+ last_urb = list_entry(urbp->ep_data->queue.prev,
+ struct c67x00_urb_priv,
+ hep_node)->urb;
+ urb->start_frame =
+ frame_add(last_urb->start_frame,
+ last_urb->number_of_packets *
+ last_urb->interval);
+ }
+ urbp->cnt = 0;
+ break;
+ }
+
+ /* Add the URB to the endpoint queue */
+ list_add_tail(&urbp->hep_node, &urbp->ep_data->queue);
+
+ /* If this is the only URB, kick start the controller */
+ if (!c67x00->urb_count++)
+ c67x00_ll_hpi_enable_sofeop(c67x00->sie);
+
+ c67x00_sched_kick(c67x00);
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ return 0;
+
+err_epdata:
+ kfree(urbp);
+err_urbp:
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+err_not_linked:
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ return ret;
+}
+
+int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
+ c67x00_release_urb(c67x00, urb);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ spin_unlock(&c67x00->lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&c67x00->lock);
+
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ return 0;
+
+ done:
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * pre: c67x00 locked, urb unlocked
+ */
+static void
+c67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status)
+{
+ struct c67x00_urb_priv *urbp;
+
+ if (!urb)
+ return;
+
+ urbp = urb->hcpriv;
+ urbp->status = status;
+
+ list_del_init(&urbp->hep_node);
+
+ c67x00_release_urb(c67x00, urb);
+ usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00), urb);
+ spin_unlock(&c67x00->lock);
+ usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb, urbp->status);
+ spin_lock(&c67x00->lock);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb,
+ int len, int periodic)
+{
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+ int bit_time;
+
+ /* According to the C67x00 BIOS user manual, page 3-18,19, the
+ * following calculations provide the full speed bit times for
+ * a transaction.
+ *
+ * FS(in) = 112.5 + 9.36*BC + HOST_DELAY
+ * FS(in,iso) = 90.5 + 9.36*BC + HOST_DELAY
+ * FS(out) = 112.5 + 9.36*BC + HOST_DELAY
+ * FS(out,iso) = 78.4 + 9.36*BC + HOST_DELAY
+ * LS(in) = 802.4 + 75.78*BC + HOST_DELAY
+ * LS(out) = 802.6 + 74.67*BC + HOST_DELAY
+ *
+ * HOST_DELAY == 106 for the c67200 and c67300.
+ */
+
+ /* make calculations in 1/100 bit times to maintain resolution */
+ if (urbp->ep_data->dev->speed == USB_SPEED_LOW) {
+ /* Low speed pipe */
+ if (usb_pipein(urb->pipe))
+ bit_time = 80240 + 7578*len;
+ else
+ bit_time = 80260 + 7467*len;
+ } else {
+ /* FS pipes */
+ if (usb_pipeisoc(urb->pipe))
+ bit_time = usb_pipein(urb->pipe) ? 9050 : 7840;
+ else
+ bit_time = 11250;
+ bit_time += 936*len;
+ }
+
+ /* Scale back down to integer bit times. Use a host delay of 106.
+ * (this is the only place it is used) */
+ bit_time = ((bit_time+50) / 100) + 106;
+
+ if (unlikely(bit_time + c67x00->bandwidth_allocated >=
+ c67x00->max_frame_bw))
+ return -EMSGSIZE;
+
+ if (unlikely(c67x00->next_td_addr + CY_TD_SIZE >=
+ c67x00->td_base_addr + SIE_TD_SIZE))
+ return -EMSGSIZE;
+
+ if (unlikely(c67x00->next_buf_addr + len >=
+ c67x00->buf_base_addr + SIE_TD_BUF_SIZE))
+ return -EMSGSIZE;
+
+ if (periodic) {
+ if (unlikely(bit_time + c67x00->periodic_bw_allocated >=
+ MAX_PERIODIC_BW(c67x00->max_frame_bw)))
+ return -EMSGSIZE;
+ c67x00->periodic_bw_allocated += bit_time;
+ }
+
+ c67x00->bandwidth_allocated += bit_time;
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * td_addr and buf_addr must be word aligned
+ */
+static int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb,
+ void *data, int len, int pid, int toggle,
+ unsigned long privdata)
+{
+ struct c67x00_td *td;
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+ const __u8 active_flag = 1, retry_cnt = 1;
+ __u8 cmd = 0;
+ int tt = 0;
+
+ if (c67x00_claim_frame_bw(c67x00, urb, len, usb_pipeisoc(urb->pipe)
+ || usb_pipeint(urb->pipe)))
+ return -EMSGSIZE; /* Not really an error, but expected */
+
+ td = kzalloc(sizeof(*td), GFP_ATOMIC);
+ if (!td)
+ return -ENOMEM;
+
+ td->pipe = urb->pipe;
+ td->ep_data = urbp->ep_data;
+
+ if ((td_udev(td)->speed == USB_SPEED_LOW) &&
+ !(c67x00->low_speed_ports & (1 << urbp->port)))
+ cmd |= PREAMBLE_EN;
+
+ switch (usb_pipetype(td->pipe)) {
+ case PIPE_ISOCHRONOUS:
+ tt = TT_ISOCHRONOUS;
+ cmd |= ISO_EN;
+ break;
+ case PIPE_CONTROL:
+ tt = TT_CONTROL;
+ break;
+ case PIPE_BULK:
+ tt = TT_BULK;
+ break;
+ case PIPE_INTERRUPT:
+ tt = TT_INTERRUPT;
+ break;
+ }
+
+ if (toggle)
+ cmd |= SEQ_SEL;
+
+ cmd |= ARM_EN;
+
+ /* SW part */
+ td->td_addr = c67x00->next_td_addr;
+ c67x00->next_td_addr = c67x00->next_td_addr + CY_TD_SIZE;
+
+ /* HW part */
+ td->ly_base_addr = __cpu_to_le16(c67x00->next_buf_addr);
+ td->port_length = __cpu_to_le16((c67x00->sie->sie_num << 15) |
+ (urbp->port << 14) | (len & 0x3FF));
+ td->pid_ep = ((pid & 0xF) << TD_PIDEP_OFFSET) |
+ (usb_pipeendpoint(td->pipe) & 0xF);
+ td->dev_addr = usb_pipedevice(td->pipe) & 0x7F;
+ td->ctrl_reg = cmd;
+ td->status = 0;
+ td->retry_cnt = (tt << TT_OFFSET) | (active_flag << 4) | retry_cnt;
+ td->residue = 0;
+ td->next_td_addr = __cpu_to_le16(c67x00->next_td_addr);
+
+ /* SW part */
+ td->data = data;
+ td->urb = urb;
+ td->privdata = privdata;
+
+ c67x00->next_buf_addr += (len + 1) & ~0x01; /* properly align */
+
+ list_add_tail(&td->td_list, &c67x00->td_list);
+ return 0;
+}
+
+static inline void c67x00_release_td(struct c67x00_td *td)
+{
+ list_del_init(&td->td_list);
+ kfree(td);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ int remaining;
+ int toggle;
+ int pid;
+ int ret = 0;
+ int maxps;
+ int need_empty;
+
+ toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe));
+ remaining = urb->transfer_buffer_length - urb->actual_length;
+
+ maxps = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+ need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
+ usb_pipeout(urb->pipe) && !(remaining % maxps);
+
+ while (remaining || need_empty) {
+ int len;
+ char *td_buf;
+
+ len = (remaining > maxps) ? maxps : remaining;
+ if (!len)
+ need_empty = 0;
+
+ pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+ td_buf = urb->transfer_buffer + urb->transfer_buffer_length -
+ remaining;
+ ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, toggle,
+ DATA_STAGE);
+ if (ret)
+ return ret; /* td wasn't created */
+
+ toggle ^= 1;
+ remaining -= len;
+ if (usb_pipecontrol(urb->pipe))
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * return 0 in case more bandwidth is available, else errorcode
+ */
+static int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ int ret;
+ int pid;
+
+ switch (urb->interval) {
+ default:
+ case SETUP_STAGE:
+ ret = c67x00_create_td(c67x00, urb, urb->setup_packet,
+ 8, USB_PID_SETUP, 0, SETUP_STAGE);
+ if (ret)
+ return ret;
+ urb->interval = SETUP_STAGE;
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe), 1);
+ break;
+ case DATA_STAGE:
+ if (urb->transfer_buffer_length) {
+ ret = c67x00_add_data_urb(c67x00, urb);
+ if (ret)
+ return ret;
+ break;
+ } /* else fallthrough */
+ case STATUS_STAGE:
+ pid = !usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+ ret = c67x00_create_td(c67x00, urb, NULL, 0, pid, 1,
+ STATUS_STAGE);
+ if (ret)
+ return ret;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * return 0 in case more bandwidth is available, else errorcode
+ */
+static int c67x00_add_int_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+
+ if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
+ urbp->ep_data->next_frame =
+ frame_add(urbp->ep_data->next_frame, urb->interval);
+ return c67x00_add_data_urb(c67x00, urb);
+ }
+ return 0;
+}
+
+static int c67x00_add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+
+ if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
+ char *td_buf;
+ int len, pid, ret;
+
+ BUG_ON(urbp->cnt >= urb->number_of_packets);
+
+ td_buf = urb->transfer_buffer +
+ urb->iso_frame_desc[urbp->cnt].offset;
+ len = urb->iso_frame_desc[urbp->cnt].length;
+ pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+
+ ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, 0,
+ urbp->cnt);
+ if (ret) {
+ printk(KERN_DEBUG "create failed: %d\n", ret);
+ urb->iso_frame_desc[urbp->cnt].actual_length = 0;
+ urb->iso_frame_desc[urbp->cnt].status = ret;
+ if (urbp->cnt + 1 == urb->number_of_packets)
+ c67x00_giveback_urb(c67x00, urb, 0);
+ }
+
+ urbp->ep_data->next_frame =
+ frame_add(urbp->ep_data->next_frame, urb->interval);
+ urbp->cnt++;
+ }
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_fill_from_list(struct c67x00_hcd *c67x00, int type,
+ int (*add)(struct c67x00_hcd *, struct urb *))
+{
+ struct c67x00_ep_data *ep_data;
+ struct urb *urb;
+
+ /* traverse every endpoint on the list */
+ list_for_each_entry(ep_data, &c67x00->list[type], node) {
+ if (!list_empty(&ep_data->queue)) {
+ /* and add the first urb */
+ /* isochronous transfer rely on this */
+ urb = list_entry(ep_data->queue.next,
+ struct c67x00_urb_priv,
+ hep_node)->urb;
+ add(c67x00, urb);
+ }
+ }
+}
+
+static void c67x00_fill_frame(struct c67x00_hcd *c67x00)
+{
+ struct c67x00_td *td, *ttd;
+
+ /* Check if we can proceed */
+ if (!list_empty(&c67x00->td_list)) {
+ dev_warn(c67x00_hcd_dev(c67x00),
+ "TD list not empty! This should not happen!\n");
+ list_for_each_entry_safe(td, ttd, &c67x00->td_list, td_list) {
+ dbg_td(c67x00, td, "Unprocessed td");
+ c67x00_release_td(td);
+ }
+ }
+
+ /* Reinitialize variables */
+ c67x00->bandwidth_allocated = 0;
+ c67x00->periodic_bw_allocated = 0;
+
+ c67x00->next_td_addr = c67x00->td_base_addr;
+ c67x00->next_buf_addr = c67x00->buf_base_addr;
+
+ /* Fill the list */
+ c67x00_fill_from_list(c67x00, PIPE_ISOCHRONOUS, c67x00_add_iso_urb);
+ c67x00_fill_from_list(c67x00, PIPE_INTERRUPT, c67x00_add_int_urb);
+ c67x00_fill_from_list(c67x00, PIPE_CONTROL, c67x00_add_ctrl_urb);
+ c67x00_fill_from_list(c67x00, PIPE_BULK, c67x00_add_data_urb);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * Get TD from C67X00
+ */
+static inline void
+c67x00_parse_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ c67x00_ll_read_mem_le16(c67x00->sie->dev,
+ td->td_addr, td, CY_TD_SIZE);
+
+ if (usb_pipein(td->pipe) && td_actual_bytes(td))
+ c67x00_ll_read_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+ td->data, td_actual_bytes(td));
+}
+
+static int c67x00_td_to_error(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ if (td->status & TD_STATUSMASK_ERR) {
+ dbg_td(c67x00, td, "ERROR_FLAG");
+ return -EILSEQ;
+ }
+ if (td->status & TD_STATUSMASK_STALL) {
+ /* dbg_td(c67x00, td, "STALL"); */
+ return -EPIPE;
+ }
+ if (td->status & TD_STATUSMASK_TMOUT) {
+ dbg_td(c67x00, td, "TIMEOUT");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static inline int c67x00_end_of_data(struct c67x00_td *td)
+{
+ int maxps, need_empty, remaining;
+ struct urb *urb = td->urb;
+ int act_bytes;
+
+ act_bytes = td_actual_bytes(td);
+
+ if (unlikely(!act_bytes))
+ return 1; /* This was an empty packet */
+
+ maxps = usb_maxpacket(td_udev(td), td->pipe, usb_pipeout(td->pipe));
+
+ if (unlikely(act_bytes < maxps))
+ return 1; /* Smaller then full packet */
+
+ remaining = urb->transfer_buffer_length - urb->actual_length;
+ need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
+ usb_pipeout(urb->pipe) && !(remaining % maxps);
+
+ if (unlikely(!remaining && !need_empty))
+ return 1;
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Remove all td's from the list which come
+ * after last_td and are meant for the same pipe.
+ * This is used when a short packet has occured */
+static inline void c67x00_clear_pipe(struct c67x00_hcd *c67x00,
+ struct c67x00_td *last_td)
+{
+ struct c67x00_td *td, *tmp;
+ td = last_td;
+ tmp = last_td;
+ while (td->td_list.next != &c67x00->td_list) {
+ td = list_entry(td->td_list.next, struct c67x00_td, td_list);
+ if (td->pipe == last_td->pipe) {
+ c67x00_release_td(td);
+ td = tmp;
+ }
+ tmp = td;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_handle_successful_td(struct c67x00_hcd *c67x00,
+ struct c67x00_td *td)
+{
+ struct urb *urb = td->urb;
+
+ if (!urb)
+ return;
+
+ urb->actual_length += td_actual_bytes(td);
+
+ switch (usb_pipetype(td->pipe)) {
+ /* isochronous tds are handled separately */
+ case PIPE_CONTROL:
+ switch (td->privdata) {
+ case SETUP_STAGE:
+ urb->interval =
+ urb->transfer_buffer_length ?
+ DATA_STAGE : STATUS_STAGE;
+ /* Don't count setup_packet with normal data: */
+ urb->actual_length = 0;
+ break;
+
+ case DATA_STAGE:
+ if (c67x00_end_of_data(td)) {
+ urb->interval = STATUS_STAGE;
+ c67x00_clear_pipe(c67x00, td);
+ }
+ break;
+
+ case STATUS_STAGE:
+ urb->interval = 0;
+ c67x00_giveback_urb(c67x00, urb, 0);
+ break;
+ }
+ break;
+
+ case PIPE_INTERRUPT:
+ case PIPE_BULK:
+ if (unlikely(c67x00_end_of_data(td))) {
+ c67x00_clear_pipe(c67x00, td);
+ c67x00_giveback_urb(c67x00, urb, 0);
+ }
+ break;
+ }
+}
+
+static void c67x00_handle_isoc(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ struct urb *urb = td->urb;
+ struct c67x00_urb_priv *urbp;
+ int cnt;
+
+ if (!urb)
+ return;
+
+ urbp = urb->hcpriv;
+ cnt = td->privdata;
+
+ if (td->status & TD_ERROR_MASK)
+ urb->error_count++;
+
+ urb->iso_frame_desc[cnt].actual_length = td_actual_bytes(td);
+ urb->iso_frame_desc[cnt].status = c67x00_td_to_error(c67x00, td);
+ if (cnt + 1 == urb->number_of_packets) /* Last packet */
+ c67x00_giveback_urb(c67x00, urb, 0);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_check_td_list - handle tds which have been processed by the c67x00
+ * pre: current_td == 0
+ */
+static inline void c67x00_check_td_list(struct c67x00_hcd *c67x00)
+{
+ struct c67x00_td *td, *tmp;
+ struct urb *urb;
+ int ack_ok;
+ int clear_endpoint;
+
+ list_for_each_entry_safe(td, tmp, &c67x00->td_list, td_list) {
+ /* get the TD */
+ c67x00_parse_td(c67x00, td);
+ urb = td->urb; /* urb can be NULL! */
+ ack_ok = 0;
+ clear_endpoint = 1;
+
+ /* Handle isochronous transfers separately */
+ if (usb_pipeisoc(td->pipe)) {
+ clear_endpoint = 0;
+ c67x00_handle_isoc(c67x00, td);
+ goto cont;
+ }
+
+ /* When an error occurs, all td's for that pipe go into an
+ * inactive state. This state matches successful transfers so
+ * we must make sure not to service them. */
+ if (td->status & TD_ERROR_MASK) {
+ c67x00_giveback_urb(c67x00, urb,
+ c67x00_td_to_error(c67x00, td));
+ goto cont;
+ }
+
+ if ((td->status & TD_STATUSMASK_NAK) || !td_sequence_ok(td) ||
+ !td_acked(td))
+ goto cont;
+
+ /* Sequence ok and acked, don't need to fix toggle */
+ ack_ok = 1;
+
+ if (unlikely(td->status & TD_STATUSMASK_OVF)) {
+ if (td_residue(td) & TD_RESIDUE_OVERFLOW) {
+ /* Overflow */
+ c67x00_giveback_urb(c67x00, urb, -EOVERFLOW);
+ goto cont;
+ }
+ }
+
+ clear_endpoint = 0;
+ c67x00_handle_successful_td(c67x00, td);
+
+cont:
+ if (clear_endpoint)
+ c67x00_clear_pipe(c67x00, td);
+ if (ack_ok)
+ usb_settoggle(td_udev(td), usb_pipeendpoint(td->pipe),
+ usb_pipeout(td->pipe),
+ !(td->ctrl_reg & SEQ_SEL));
+ /* next in list could have been removed, due to clear_pipe! */
+ tmp = list_entry(td->td_list.next, typeof(*td), td_list);
+ c67x00_release_td(td);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline int c67x00_all_tds_processed(struct c67x00_hcd *c67x00)
+{
+ /* If all tds are processed, we can check the previous frame (if
+ * there was any) and start our next frame.
+ */
+ return !c67x00_ll_husb_get_current_td(c67x00->sie);
+}
+
+/**
+ * Send td to C67X00
+ */
+static void c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ int len = td_length(td);
+
+ if (len && ((td->pid_ep & TD_PIDEPMASK_PID) != TD_PID_IN))
+ c67x00_ll_write_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+ td->data, len);
+
+ c67x00_ll_write_mem_le16(c67x00->sie->dev,
+ td->td_addr, td, CY_TD_SIZE);
+}
+
+static void c67x00_send_frame(struct c67x00_hcd *c67x00)
+{
+ struct c67x00_td *td;
+
+ if (list_empty(&c67x00->td_list))
+ dev_warn(c67x00_hcd_dev(c67x00),
+ "%s: td list should not be empty here!\n",
+ __func__);
+
+ list_for_each_entry(td, &c67x00->td_list, td_list) {
+ if (td->td_list.next == &c67x00->td_list)
+ td->next_td_addr = 0; /* Last td in list */
+
+ c67x00_send_td(c67x00, td);
+ }
+
+ c67x00_ll_husb_set_current_td(c67x00->sie, c67x00->td_base_addr);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_do_work - Schedulers state machine
+ */
+static void c67x00_do_work(struct c67x00_hcd *c67x00)
+{
+ spin_lock(&c67x00->lock);
+ /* Make sure all tds are processed */
+ if (!c67x00_all_tds_processed(c67x00))
+ goto out;
+
+ c67x00_check_td_list(c67x00);
+
+ /* no td's are being processed (current == 0)
+ * and all have been "checked" */
+ complete(&c67x00->endpoint_disable);
+
+ if (!list_empty(&c67x00->td_list))
+ goto out;
+
+ c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
+ if (c67x00->current_frame == c67x00->last_frame)
+ goto out; /* Don't send tds in same frame */
+ c67x00->last_frame = c67x00->current_frame;
+
+ /* If no urbs are scheduled, our work is done */
+ if (!c67x00->urb_count) {
+ c67x00_ll_hpi_disable_sofeop(c67x00->sie);
+ goto out;
+ }
+
+ c67x00_fill_frame(c67x00);
+ if (!list_empty(&c67x00->td_list))
+ /* TD's have been added to the frame */
+ c67x00_send_frame(c67x00);
+
+ out:
+ spin_unlock(&c67x00->lock);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_sched_tasklet(unsigned long __c67x00)
+{
+ struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00;
+ c67x00_do_work(c67x00);
+}
+
+void c67x00_sched_kick(struct c67x00_hcd *c67x00)
+{
+ tasklet_hi_schedule(&c67x00->tasklet);
+}
+
+int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00)
+{
+ tasklet_init(&c67x00->tasklet, c67x00_sched_tasklet,
+ (unsigned long)c67x00);
+ return 0;
+}
+
+void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00)
+{
+ tasklet_kill(&c67x00->tasklet);
+}
diff --git a/drivers/usb/c67x00/c67x00.h b/drivers/usb/c67x00/c67x00.h
new file mode 100644
index 00000000000..a26e9ded0f3
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00.h
@@ -0,0 +1,294 @@
+/*
+ * c67x00.h: Cypress C67X00 USB register and field definitions
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#ifndef _USB_C67X00_H
+#define _USB_C67X00_H
+
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+/* ---------------------------------------------------------------------
+ * Cypress C67x00 register definitions
+ */
+
+/* Hardware Revision Register */
+#define HW_REV_REG 0xC004
+
+/* General USB registers */
+/* ===================== */
+
+/* USB Control Register */
+#define USB_CTL_REG(x) ((x) ? 0xC0AA : 0xC08A)
+
+#define LOW_SPEED_PORT(x) ((x) ? 0x0800 : 0x0400)
+#define HOST_MODE 0x0200
+#define PORT_RES_EN(x) ((x) ? 0x0100 : 0x0080)
+#define SOF_EOP_EN(x) ((x) ? 0x0002 : 0x0001)
+
+/* USB status register - Notice it has different content in hcd/udc mode */
+#define USB_STAT_REG(x) ((x) ? 0xC0B0 : 0xC090)
+
+#define EP0_IRQ_FLG 0x0001
+#define EP1_IRQ_FLG 0x0002
+#define EP2_IRQ_FLG 0x0004
+#define EP3_IRQ_FLG 0x0008
+#define EP4_IRQ_FLG 0x0010
+#define EP5_IRQ_FLG 0x0020
+#define EP6_IRQ_FLG 0x0040
+#define EP7_IRQ_FLG 0x0080
+#define RESET_IRQ_FLG 0x0100
+#define SOF_EOP_IRQ_FLG 0x0200
+#define ID_IRQ_FLG 0x4000
+#define VBUS_IRQ_FLG 0x8000
+
+/* USB Host only registers */
+/* ======================= */
+
+/* Host n Control Register */
+#define HOST_CTL_REG(x) ((x) ? 0xC0A0 : 0xC080)
+
+#define PREAMBLE_EN 0x0080 /* Preamble enable */
+#define SEQ_SEL 0x0040 /* Data Toggle Sequence Bit Select */
+#define ISO_EN 0x0010 /* Isochronous enable */
+#define ARM_EN 0x0001 /* Arm operation */
+
+/* Host n Interrupt Enable Register */
+#define HOST_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
+
+#define SOF_EOP_IRQ_EN 0x0200 /* SOF/EOP Interrupt Enable */
+#define SOF_EOP_TMOUT_IRQ_EN 0x0800 /* SOF/EOP Timeout Interrupt Enable */
+#define ID_IRQ_EN 0x4000 /* ID interrupt enable */
+#define VBUS_IRQ_EN 0x8000 /* VBUS interrupt enable */
+#define DONE_IRQ_EN 0x0001 /* Done Interrupt Enable */
+
+/* USB status register */
+#define HOST_STAT_MASK 0x02FD
+#define PORT_CONNECT_CHANGE(x) ((x) ? 0x0020 : 0x0010)
+#define PORT_SE0_STATUS(x) ((x) ? 0x0008 : 0x0004)
+
+/* Host Frame Register */
+#define HOST_FRAME_REG(x) ((x) ? 0xC0B6 : 0xC096)
+
+#define HOST_FRAME_MASK 0x07FF
+
+/* USB Peripheral only registers */
+/* ============================= */
+
+/* Device n Port Sel reg */
+#define DEVICE_N_PORT_SEL(x) ((x) ? 0xC0A4 : 0xC084)
+
+/* Device n Interrupt Enable Register */
+#define DEVICE_N_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
+
+#define DEVICE_N_ENDPOINT_N_CTL_REG(dev, ep) ((dev) \
+ ? (0x0280 + (ep << 4)) \
+ : (0x0200 + (ep << 4)))
+#define DEVICE_N_ENDPOINT_N_STAT_REG(dev, ep) ((dev) \
+ ? (0x0286 + (ep << 4)) \
+ : (0x0206 + (ep << 4)))
+
+#define DEVICE_N_ADDRESS(dev) ((dev) ? (0xC0AE) : (0xC08E))
+
+/* HPI registers */
+/* ============= */
+
+/* HPI Status register */
+#define SOFEOP_FLG(x) (1 << ((x) ? 12 : 10))
+#define SIEMSG_FLG(x) (1 << (4 + (x)))
+#define RESET_FLG(x) ((x) ? 0x0200 : 0x0002)
+#define DONE_FLG(x) (1 << (2 + (x)))
+#define RESUME_FLG(x) (1 << (6 + (x)))
+#define MBX_OUT_FLG 0x0001 /* Message out available */
+#define MBX_IN_FLG 0x0100
+#define ID_FLG 0x4000
+#define VBUS_FLG 0x8000
+
+/* Interrupt routing register */
+#define HPI_IRQ_ROUTING_REG 0x0142
+
+#define HPI_SWAP_ENABLE(x) ((x) ? 0x0100 : 0x0001)
+#define RESET_TO_HPI_ENABLE(x) ((x) ? 0x0200 : 0x0002)
+#define DONE_TO_HPI_ENABLE(x) ((x) ? 0x0008 : 0x0004)
+#define RESUME_TO_HPI_ENABLE(x) ((x) ? 0x0080 : 0x0040)
+#define SOFEOP_TO_HPI_EN(x) ((x) ? 0x2000 : 0x0800)
+#define SOFEOP_TO_CPU_EN(x) ((x) ? 0x1000 : 0x0400)
+#define ID_TO_HPI_ENABLE 0x4000
+#define VBUS_TO_HPI_ENABLE 0x8000
+
+/* SIE msg registers */
+#define SIEMSG_REG(x) ((x) ? 0x0148 : 0x0144)
+
+#define HUSB_TDListDone 0x1000
+
+#define SUSB_EP0_MSG 0x0001
+#define SUSB_EP1_MSG 0x0002
+#define SUSB_EP2_MSG 0x0004
+#define SUSB_EP3_MSG 0x0008
+#define SUSB_EP4_MSG 0x0010
+#define SUSB_EP5_MSG 0x0020
+#define SUSB_EP6_MSG 0x0040
+#define SUSB_EP7_MSG 0x0080
+#define SUSB_RST_MSG 0x0100
+#define SUSB_SOF_MSG 0x0200
+#define SUSB_CFG_MSG 0x0400
+#define SUSB_SUS_MSG 0x0800
+#define SUSB_ID_MSG 0x4000
+#define SUSB_VBUS_MSG 0x8000
+
+/* BIOS interrupt routines */
+
+#define SUSBx_RECEIVE_INT(x) ((x) ? 97 : 81)
+#define SUSBx_SEND_INT(x) ((x) ? 96 : 80)
+
+#define SUSBx_DEV_DESC_VEC(x) ((x) ? 0x00D4 : 0x00B4)
+#define SUSBx_CONF_DESC_VEC(x) ((x) ? 0x00D6 : 0x00B6)
+#define SUSBx_STRING_DESC_VEC(x) ((x) ? 0x00D8 : 0x00B8)
+
+#define CY_HCD_BUF_ADDR 0x500 /* Base address for host */
+#define SIE_TD_SIZE 0x200 /* size of the td list */
+#define SIE_TD_BUF_SIZE 0x400 /* size of the data buffer */
+
+#define SIE_TD_OFFSET(host) ((host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0)
+#define SIE_BUF_OFFSET(host) (SIE_TD_OFFSET(host) + SIE_TD_SIZE)
+
+/* Base address of HCD + 2 x TD_SIZE + 2 x TD_BUF_SIZE */
+#define CY_UDC_REQ_HEADER_BASE 0x1100
+/* 8- byte request headers for IN/OUT transfers */
+#define CY_UDC_REQ_HEADER_SIZE 8
+
+#define CY_UDC_REQ_HEADER_ADDR(ep_num) (CY_UDC_REQ_HEADER_BASE + \
+ ((ep_num) * CY_UDC_REQ_HEADER_SIZE))
+#define CY_UDC_DESC_BASE_ADDRESS (CY_UDC_REQ_HEADER_ADDR(8))
+
+#define CY_UDC_BIOS_REPLACE_BASE 0x1800
+#define CY_UDC_REQ_BUFFER_BASE 0x2000
+#define CY_UDC_REQ_BUFFER_SIZE 0x0400
+#define CY_UDC_REQ_BUFFER_ADDR(ep_num) (CY_UDC_REQ_BUFFER_BASE + \
+ ((ep_num) * CY_UDC_REQ_BUFFER_SIZE))
+
+/* ---------------------------------------------------------------------
+ * Driver data structures
+ */
+
+struct c67x00_device;
+
+/**
+ * struct c67x00_sie - Common data associated with a SIE
+ * @lock: lock to protect this struct and the associated chip registers
+ * @private_data: subdriver dependent data
+ * @irq: subdriver dependent irq handler, set NULL when not used
+ * @dev: link to common driver structure
+ * @sie_num: SIE number on chip, starting from 0
+ * @mode: SIE mode (host/peripheral/otg/not used)
+ */
+struct c67x00_sie {
+ /* Entries to be used by the subdrivers */
+ spinlock_t lock; /* protect this structure */
+ void *private_data;
+ void (*irq) (struct c67x00_sie *sie, u16 int_status, u16 msg);
+
+ /* Read only: */
+ struct c67x00_device *dev;
+ int sie_num;
+ int mode;
+};
+
+#define sie_dev(s) (&(s)->dev->pdev->dev)
+
+/**
+ * struct c67x00_lcp
+ */
+struct c67x00_lcp {
+ /* Internal use only */
+ struct mutex mutex;
+ struct completion msg_received;
+ u16 last_msg;
+};
+
+/*
+ * struct c67x00_hpi
+ */
+struct c67x00_hpi {
+ void __iomem *base;
+ int regstep;
+ spinlock_t lock;
+ struct c67x00_lcp lcp;
+};
+
+#define C67X00_SIES 2
+#define C67X00_PORTS 2
+
+/**
+ * struct c67x00_device - Common data associated with a c67x00 instance
+ * @hpi: hpi addresses
+ * @sie: array of sie's on this chip
+ * @pdev: platform device of instance
+ * @pdata: configuration provided by the platform
+ */
+struct c67x00_device {
+ struct c67x00_hpi hpi;
+ struct c67x00_sie sie[C67X00_SIES];
+ struct platform_device *pdev;
+ struct c67x00_platform_data *pdata;
+};
+
+/* ---------------------------------------------------------------------
+ * Low level interface functions
+ */
+
+/* Host Port Interface (HPI) functions */
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev);
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev);
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie);
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie);
+
+/* General functions */
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num);
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie);
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits);
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie);
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len);
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len);
+
+/* Host specific functions */
+void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value);
+void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port);
+void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr);
+u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie);
+u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie);
+void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie);
+void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port);
+
+/* Called by c67x00_irq to handle lcp interrupts */
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status);
+
+/* Setup and teardown */
+void c67x00_ll_init(struct c67x00_device *dev);
+void c67x00_ll_release(struct c67x00_device *dev);
+int c67x00_ll_reset(struct c67x00_device *dev);
+
+#endif /* _USB_C67X00_H */
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index e819e5359d5..3e69266e1f4 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -394,7 +394,9 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
if (!io->urbs)
goto nomem;
- urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
+ urb_flags = URB_NO_INTERRUPT;
+ if (dma)
+ urb_flags |= URB_NO_TRANSFER_DMA_MAP;
if (usb_pipein(pipe))
urb_flags |= URB_SHORT_NOT_OK;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index f7b54651dd4..6e784d2db42 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -231,6 +231,26 @@ config SUPERH_BUILT_IN_M66592
However, this problem is improved if change a value of
NET_IP_ALIGN to 4.
+config USB_GADGET_PXA27X
+ boolean "PXA 27x"
+ depends on ARCH_PXA && PXA27x
+ help
+ Intel's PXA 27x series XScale ARM v5TE processors include
+ an integrated full speed USB 1.1 device controller.
+
+ It has up to 23 endpoints, as well as endpoint zero (for
+ control transfers).
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "pxa27x_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_PXA27X
+ tristate
+ depends on USB_GADGET_PXA27X
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index c3aab80b6c7..12357255d74 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
+obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index bb93bdd7659..8d61ea67a81 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -235,10 +235,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
-#ifdef CONFIG_USB_GADGET_PXA27X
-#define DEV_CONFIG_CDC
-#endif
-
#ifdef CONFIG_USB_GADGET_S3C2410
#define DEV_CONFIG_CDC
#endif
@@ -270,6 +266,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define DEV_CONFIG_SUBSET
+#endif
+
#ifdef CONFIG_USB_GADGET_SUPERH
#define DEV_CONFIG_SUBSET
#endif
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index bf3f946fd45..47bb9f09a1a 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -2307,6 +2307,29 @@ static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
return rc;
}
+static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+ int rc;
+
+ DBG(fsg, "bulk-in set wedge\n");
+ rc = usb_ep_set_wedge(fsg->bulk_in);
+ if (rc == -EAGAIN)
+ VDBG(fsg, "delayed bulk-in endpoint wedge\n");
+ while (rc != 0) {
+ if (rc != -EAGAIN) {
+ WARN(fsg, "usb_ep_set_wedge -> %d\n", rc);
+ rc = 0;
+ break;
+ }
+
+ /* Wait for a short time and then try again */
+ if (msleep_interruptible(100) != 0)
+ return -EINTR;
+ rc = usb_ep_set_wedge(fsg->bulk_in);
+ }
+ return rc;
+}
+
static int pad_with_zeros(struct fsg_dev *fsg)
{
struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
@@ -2957,7 +2980,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
* We aren't required to halt the OUT endpoint; instead
* we can simply accept and discard any data received
* until the next reset. */
- halt_bulk_in_endpoint(fsg);
+ wedge_bulk_in_endpoint(fsg);
set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
return -EINVAL;
}
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
new file mode 100644
index 00000000000..75eba202f73
--- /dev/null
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -0,0 +1,2404 @@
+/*
+ * Handles the Intel 27x USB Device Controller (UDC)
+ *
+ * Inspired by original driver by Frank Becker, David Brownell, and others.
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/hardware.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/arch/udc.h>
+
+#include "pxa27x_udc.h"
+
+/*
+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x
+ * series processors.
+ *
+ * Such controller drivers work with a gadget driver. The gadget driver
+ * returns descriptors, implements configuration and data protocols used
+ * by the host to interact with this device, and allocates endpoints to
+ * the different protocol interfaces. The controller driver virtualizes
+ * usb hardware so that the gadget drivers will be more portable.
+ *
+ * This UDC hardware wants to implement a bit too much USB protocol. The
+ * biggest issues are: that the endpoints have to be set up before the
+ * controller can be enabled (minor, and not uncommon); and each endpoint
+ * can only have one configuration, interface and alternative interface
+ * number (major, and very unusual). Once set up, these cannot be changed
+ * without a controller reset.
+ *
+ * The workaround is to setup all combinations necessary for the gadgets which
+ * will work with this driver. This is done in pxa_udc structure, statically.
+ * See pxa_udc, udc_usb_ep versus pxa_ep, and matching function find_pxa_ep.
+ * (You could modify this if needed. Some drivers have a "fifo_mode" module
+ * parameter to facilitate such changes.)
+ *
+ * The combinations have been tested with these gadgets :
+ * - zero gadget
+ * - file storage gadget
+ * - ether gadget
+ *
+ * The driver doesn't use DMA, only IO access and IRQ callbacks. No use is
+ * made of UDC's double buffering either. USB "On-The-Go" is not implemented.
+ *
+ * All the requests are handled the same way :
+ * - the drivers tries to handle the request directly to the IO
+ * - if the IO fifo is not big enough, the remaining is send/received in
+ * interrupt handling.
+ */
+
+#define DRIVER_VERSION "2008-04-18"
+#define DRIVER_DESC "PXA 27x USB Device Controller driver"
+
+static const char driver_name[] = "pxa27x_udc";
+static struct pxa_udc *the_controller;
+
+static void handle_ep(struct pxa_ep *ep);
+
+/*
+ * Debug filesystem
+ */
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+
+static int state_dbg_show(struct seq_file *s, void *p)
+{
+ struct pxa_udc *udc = s->private;
+ int pos = 0, ret;
+ u32 tmp;
+
+ ret = -ENODEV;
+ if (!udc->driver)
+ goto out;
+
+ /* basic device status */
+ pos += seq_printf(s, DRIVER_DESC "\n"
+ "%s version: %s\nGadget driver: %s\n",
+ driver_name, DRIVER_VERSION,
+ udc->driver ? udc->driver->driver.name : "(none)");
+
+ tmp = udc_readl(udc, UDCCR);
+ pos += seq_printf(s,
+ "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), "
+ "con=%d,inter=%d,altinter=%d\n", tmp,
+ (tmp & UDCCR_OEN) ? " oen":"",
+ (tmp & UDCCR_AALTHNP) ? " aalthnp":"",
+ (tmp & UDCCR_AHNP) ? " rem" : "",
+ (tmp & UDCCR_BHNP) ? " rstir" : "",
+ (tmp & UDCCR_DWRE) ? " dwre" : "",
+ (tmp & UDCCR_SMAC) ? " smac" : "",
+ (tmp & UDCCR_EMCE) ? " emce" : "",
+ (tmp & UDCCR_UDR) ? " udr" : "",
+ (tmp & UDCCR_UDA) ? " uda" : "",
+ (tmp & UDCCR_UDE) ? " ude" : "",
+ (tmp & UDCCR_ACN) >> UDCCR_ACN_S,
+ (tmp & UDCCR_AIN) >> UDCCR_AIN_S,
+ (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S);
+ /* registers for device and ep0 */
+ pos += seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n",
+ udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1));
+ pos += seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n",
+ udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1));
+ pos += seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR));
+ pos += seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, "
+ "reconfig=%lu\n",
+ udc->stats.irqs_reset, udc->stats.irqs_suspend,
+ udc->stats.irqs_resume, udc->stats.irqs_reconfig);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int queues_dbg_show(struct seq_file *s, void *p)
+{
+ struct pxa_udc *udc = s->private;
+ struct pxa_ep *ep;
+ struct pxa27x_request *req;
+ int pos = 0, i, maxpkt, ret;
+
+ ret = -ENODEV;
+ if (!udc->driver)
+ goto out;
+
+ /* dump endpoint queues */
+ for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ maxpkt = ep->fifo_size;
+ pos += seq_printf(s, "%-12s max_pkt=%d %s\n",
+ EPNAME(ep), maxpkt, "pio");
+
+ if (list_empty(&ep->queue)) {
+ pos += seq_printf(s, "\t(nothing queued)\n");
+ continue;
+ }
+
+ list_for_each_entry(req, &ep->queue, queue) {
+ pos += seq_printf(s, "\treq %p len %d/%d buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int eps_dbg_show(struct seq_file *s, void *p)
+{
+ struct pxa_udc *udc = s->private;
+ struct pxa_ep *ep;
+ int pos = 0, i, ret;
+ u32 tmp;
+
+ ret = -ENODEV;
+ if (!udc->driver)
+ goto out;
+
+ ep = &udc->pxa_ep[0];
+ tmp = udc_ep_readl(ep, UDCCSR);
+ pos += seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", tmp,
+ (tmp & UDCCSR0_SA) ? " sa" : "",
+ (tmp & UDCCSR0_RNE) ? " rne" : "",
+ (tmp & UDCCSR0_FST) ? " fst" : "",
+ (tmp & UDCCSR0_SST) ? " sst" : "",
+ (tmp & UDCCSR0_DME) ? " dme" : "",
+ (tmp & UDCCSR0_IPR) ? " ipr" : "",
+ (tmp & UDCCSR0_OPC) ? " opc" : "");
+ for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR);
+ pos += seq_printf(s, "%-12s: "
+ "IN %lu(%lu reqs), OUT %lu(%lu reqs), "
+ "irqs=%lu, udccr=0x%08x, udccsr=0x%03x, "
+ "udcbcr=%d\n",
+ EPNAME(ep),
+ ep->stats.in_bytes, ep->stats.in_ops,
+ ep->stats.out_bytes, ep->stats.out_ops,
+ ep->stats.irqs,
+ tmp, udc_ep_readl(ep, UDCCSR),
+ udc_ep_readl(ep, UDCBCR));
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int eps_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, eps_dbg_show, inode->i_private);
+}
+
+static int queues_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, queues_dbg_show, inode->i_private);
+}
+
+static int state_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, state_dbg_show, inode->i_private);
+}
+
+static const struct file_operations state_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = state_dbg_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static const struct file_operations queues_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = queues_dbg_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static const struct file_operations eps_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = eps_dbg_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static void pxa_init_debugfs(struct pxa_udc *udc)
+{
+ struct dentry *root, *state, *queues, *eps;
+
+ root = debugfs_create_dir(udc->gadget.name, NULL);
+ if (IS_ERR(root) || !root)
+ goto err_root;
+
+ state = debugfs_create_file("udcstate", 0400, root, udc,
+ &state_dbg_fops);
+ if (!state)
+ goto err_state;
+ queues = debugfs_create_file("queues", 0400, root, udc,
+ &queues_dbg_fops);
+ if (!queues)
+ goto err_queues;
+ eps = debugfs_create_file("epstate", 0400, root, udc,
+ &eps_dbg_fops);
+ if (!queues)
+ goto err_eps;
+
+ udc->debugfs_root = root;
+ udc->debugfs_state = state;
+ udc->debugfs_queues = queues;
+ udc->debugfs_eps = eps;
+ return;
+err_eps:
+ debugfs_remove(eps);
+err_queues:
+ debugfs_remove(queues);
+err_state:
+ debugfs_remove(root);
+err_root:
+ dev_err(udc->dev, "debugfs is not available\n");
+}
+
+static void pxa_cleanup_debugfs(struct pxa_udc *udc)
+{
+ debugfs_remove(udc->debugfs_eps);
+ debugfs_remove(udc->debugfs_queues);
+ debugfs_remove(udc->debugfs_state);
+ debugfs_remove(udc->debugfs_root);
+ udc->debugfs_eps = NULL;
+ udc->debugfs_queues = NULL;
+ udc->debugfs_state = NULL;
+ udc->debugfs_root = NULL;
+}
+
+#else
+static inline void pxa_init_debugfs(struct pxa_udc *udc)
+{
+}
+
+static inline void pxa_cleanup_debugfs(struct pxa_udc *udc)
+{
+}
+#endif
+
+/**
+ * is_match_usb_pxa - check if usb_ep and pxa_ep match
+ * @udc_usb_ep: usb endpoint
+ * @ep: pxa endpoint
+ * @config: configuration required in pxa_ep
+ * @interface: interface required in pxa_ep
+ * @altsetting: altsetting required in pxa_ep
+ *
+ * Returns 1 if all criteria match between pxa and usb endpoint, 0 otherwise
+ */
+static int is_match_usb_pxa(struct udc_usb_ep *udc_usb_ep, struct pxa_ep *ep,
+ int config, int interface, int altsetting)
+{
+ if (usb_endpoint_num(&udc_usb_ep->desc) != ep->addr)
+ return 0;
+ if (usb_endpoint_dir_in(&udc_usb_ep->desc) != ep->dir_in)
+ return 0;
+ if (usb_endpoint_type(&udc_usb_ep->desc) != ep->type)
+ return 0;
+ if ((ep->config != config) || (ep->interface != interface)
+ || (ep->alternate != altsetting))
+ return 0;
+ return 1;
+}
+
+/**
+ * find_pxa_ep - find pxa_ep structure matching udc_usb_ep
+ * @udc: pxa udc
+ * @udc_usb_ep: udc_usb_ep structure
+ *
+ * Match udc_usb_ep and all pxa_ep available, to see if one matches.
+ * This is necessary because of the strong pxa hardware restriction requiring
+ * that once pxa endpoints are initialized, their configuration is freezed, and
+ * no change can be made to their address, direction, or in which configuration,
+ * interface or altsetting they are active ... which differs from more usual
+ * models which have endpoints be roughly just addressable fifos, and leave
+ * configuration events up to gadget drivers (like all control messages).
+ *
+ * Note that there is still a blurred point here :
+ * - we rely on UDCCR register "active interface" and "active altsetting".
+ * This is a nonsense in regard of USB spec, where multiple interfaces are
+ * active at the same time.
+ * - if we knew for sure that the pxa can handle multiple interface at the
+ * same time, assuming Intel's Developer Guide is wrong, this function
+ * should be reviewed, and a cache of couples (iface, altsetting) should
+ * be kept in the pxa_udc structure. In this case this function would match
+ * against the cache of couples instead of the "last altsetting" set up.
+ *
+ * Returns the matched pxa_ep structure or NULL if none found
+ */
+static struct pxa_ep *find_pxa_ep(struct pxa_udc *udc,
+ struct udc_usb_ep *udc_usb_ep)
+{
+ int i;
+ struct pxa_ep *ep;
+ int cfg = udc->config;
+ int iface = udc->last_interface;
+ int alt = udc->last_alternate;
+
+ if (udc_usb_ep == &udc->udc_usb_ep[0])
+ return &udc->pxa_ep[0];
+
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ if (is_match_usb_pxa(udc_usb_ep, ep, cfg, iface, alt))
+ return ep;
+ }
+ return NULL;
+}
+
+/**
+ * update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep
+ * @udc: pxa udc
+ *
+ * Context: in_interrupt()
+ *
+ * Updates all pxa_ep fields in udc_usb_ep structures, if this field was
+ * previously set up (and is not NULL). The update is necessary is a
+ * configuration change or altsetting change was issued by the USB host.
+ */
+static void update_pxa_ep_matches(struct pxa_udc *udc)
+{
+ int i;
+ struct udc_usb_ep *udc_usb_ep;
+
+ for (i = 1; i < NR_USB_ENDPOINTS; i++) {
+ udc_usb_ep = &udc->udc_usb_ep[i];
+ if (udc_usb_ep->pxa_ep)
+ udc_usb_ep->pxa_ep = find_pxa_ep(udc, udc_usb_ep);
+ }
+}
+
+/**
+ * pio_irq_enable - Enables irq generation for one endpoint
+ * @ep: udc endpoint
+ */
+static void pio_irq_enable(struct pxa_ep *ep)
+{
+ struct pxa_udc *udc = ep->dev;
+ int index = EPIDX(ep);
+ u32 udcicr0 = udc_readl(udc, UDCICR0);
+ u32 udcicr1 = udc_readl(udc, UDCICR1);
+
+ if (index < 16)
+ udc_writel(udc, UDCICR0, udcicr0 | (3 << (index * 2)));
+ else
+ udc_writel(udc, UDCICR1, udcicr1 | (3 << ((index - 16) * 2)));
+}
+
+/**
+ * pio_irq_disable - Disables irq generation for one endpoint
+ * @ep: udc endpoint
+ * @index: endpoint number
+ */
+static void pio_irq_disable(struct pxa_ep *ep)
+{
+ struct pxa_udc *udc = ep->dev;
+ int index = EPIDX(ep);
+ u32 udcicr0 = udc_readl(udc, UDCICR0);
+ u32 udcicr1 = udc_readl(udc, UDCICR1);
+
+ if (index < 16)
+ udc_writel(udc, UDCICR0, udcicr0 & ~(3 << (index * 2)));
+ else
+ udc_writel(udc, UDCICR1, udcicr1 & ~(3 << ((index - 16) * 2)));
+}
+
+/**
+ * udc_set_mask_UDCCR - set bits in UDCCR
+ * @udc: udc device
+ * @mask: bits to set in UDCCR
+ *
+ * Sets bits in UDCCR, leaving DME and FST bits as they were.
+ */
+static inline void udc_set_mask_UDCCR(struct pxa_udc *udc, int mask)
+{
+ u32 udccr = udc_readl(udc, UDCCR);
+ udc_writel(udc, UDCCR,
+ (udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS));
+}
+
+/**
+ * udc_clear_mask_UDCCR - clears bits in UDCCR
+ * @udc: udc device
+ * @mask: bit to clear in UDCCR
+ *
+ * Clears bits in UDCCR, leaving DME and FST bits as they were.
+ */
+static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask)
+{
+ u32 udccr = udc_readl(udc, UDCCR);
+ udc_writel(udc, UDCCR,
+ (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS));
+}
+
+/**
+ * ep_count_bytes_remain - get how many bytes in udc endpoint
+ * @ep: udc endpoint
+ *
+ * Returns number of bytes in OUT fifos. Broken for IN fifos (-EOPNOTSUPP)
+ */
+static int ep_count_bytes_remain(struct pxa_ep *ep)
+{
+ if (ep->dir_in)
+ return -EOPNOTSUPP;
+ return udc_ep_readl(ep, UDCBCR) & 0x3ff;
+}
+
+/**
+ * ep_is_empty - checks if ep has byte ready for reading
+ * @ep: udc endpoint
+ *
+ * If endpoint is the control endpoint, checks if there are bytes in the
+ * control endpoint fifo. If endpoint is a data endpoint, checks if bytes
+ * are ready for reading on OUT endpoint.
+ *
+ * Returns 0 if ep not empty, 1 if ep empty, -EOPNOTSUPP if IN endpoint
+ */
+static int ep_is_empty(struct pxa_ep *ep)
+{
+ int ret;
+
+ if (!is_ep0(ep) && ep->dir_in)
+ return -EOPNOTSUPP;
+ if (is_ep0(ep))
+ ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR0_RNE);
+ else
+ ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNE);
+ return ret;
+}
+
+/**
+ * ep_is_full - checks if ep has place to write bytes
+ * @ep: udc endpoint
+ *
+ * If endpoint is not the control endpoint and is an IN endpoint, checks if
+ * there is place to write bytes into the endpoint.
+ *
+ * Returns 0 if ep not full, 1 if ep full, -EOPNOTSUPP if OUT endpoint
+ */
+static int ep_is_full(struct pxa_ep *ep)
+{
+ if (is_ep0(ep))
+ return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_IPR);
+ if (!ep->dir_in)
+ return -EOPNOTSUPP;
+ return (!(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNF));
+}
+
+/**
+ * epout_has_pkt - checks if OUT endpoint fifo has a packet available
+ * @ep: pxa endpoint
+ *
+ * Returns 1 if a complete packet is available, 0 if not, -EOPNOTSUPP for IN ep.
+ */
+static int epout_has_pkt(struct pxa_ep *ep)
+{
+ if (!is_ep0(ep) && ep->dir_in)
+ return -EOPNOTSUPP;
+ if (is_ep0(ep))
+ return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_OPC);
+ return (udc_ep_readl(ep, UDCCSR) & UDCCSR_PC);
+}
+
+/**
+ * set_ep0state - Set ep0 automata state
+ * @dev: udc device
+ * @state: state
+ */
+static void set_ep0state(struct pxa_udc *udc, int state)
+{
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+ char *old_stname = EP0_STNAME(udc);
+
+ udc->ep0state = state;
+ ep_dbg(ep, "state=%s->%s, udccsr0=0x%03x, udcbcr=%d\n", old_stname,
+ EP0_STNAME(udc), udc_ep_readl(ep, UDCCSR),
+ udc_ep_readl(ep, UDCBCR));
+}
+
+/**
+ * ep0_idle - Put control endpoint into idle state
+ * @dev: udc device
+ */
+static void ep0_idle(struct pxa_udc *dev)
+{
+ set_ep0state(dev, WAIT_FOR_SETUP);
+}
+
+/**
+ * inc_ep_stats_reqs - Update ep stats counts
+ * @ep: physical endpoint
+ * @req: usb request
+ * @is_in: ep direction (USB_DIR_IN or 0)
+ *
+ */
+static void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in)
+{
+ if (is_in)
+ ep->stats.in_ops++;
+ else
+ ep->stats.out_ops++;
+}
+
+/**
+ * inc_ep_stats_bytes - Update ep stats counts
+ * @ep: physical endpoint
+ * @count: bytes transfered on endpoint
+ * @req: usb request
+ * @is_in: ep direction (USB_DIR_IN or 0)
+ */
+static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
+{
+ if (is_in)
+ ep->stats.in_bytes += count;
+ else
+ ep->stats.out_bytes += count;
+}
+
+/**
+ * pxa_ep_setup - Sets up an usb physical endpoint
+ * @ep: pxa27x physical endpoint
+ *
+ * Find the physical pxa27x ep, and setup its UDCCR
+ */
+static __init void pxa_ep_setup(struct pxa_ep *ep)
+{
+ u32 new_udccr;
+
+ new_udccr = ((ep->config << UDCCONR_CN_S) & UDCCONR_CN)
+ | ((ep->interface << UDCCONR_IN_S) & UDCCONR_IN)
+ | ((ep->alternate << UDCCONR_AISN_S) & UDCCONR_AISN)
+ | ((EPADDR(ep) << UDCCONR_EN_S) & UDCCONR_EN)
+ | ((EPXFERTYPE(ep) << UDCCONR_ET_S) & UDCCONR_ET)
+ | ((ep->dir_in) ? UDCCONR_ED : 0)
+ | ((ep->fifo_size << UDCCONR_MPS_S) & UDCCONR_MPS)
+ | UDCCONR_EE;
+
+ udc_ep_writel(ep, UDCCR, new_udccr);
+}
+
+/**
+ * pxa_eps_setup - Sets up all usb physical endpoints
+ * @dev: udc device
+ *
+ * Setup all pxa physical endpoints, except ep0
+ */
+static __init void pxa_eps_setup(struct pxa_udc *dev)
+{
+ unsigned int i;
+
+ dev_dbg(dev->dev, "%s: dev=%p\n", __func__, dev);
+
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++)
+ pxa_ep_setup(&dev->pxa_ep[i]);
+}
+
+/**
+ * pxa_ep_alloc_request - Allocate usb request
+ * @_ep: usb endpoint
+ * @gfp_flags:
+ *
+ * For the pxa27x, these can just wrap kmalloc/kfree. gadget drivers
+ * must still pass correctly initialized endpoints, since other controller
+ * drivers may care about how it's currently set up (dma issues etc).
+ */
+static struct usb_request *
+pxa_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct pxa27x_request *req;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req || !_ep)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+ req->in_use = 0;
+ req->udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+
+ return &req->req;
+}
+
+/**
+ * pxa_ep_free_request - Free usb request
+ * @_ep: usb endpoint
+ * @_req: usb request
+ *
+ * Wrapper around kfree to free _req
+ */
+static void pxa_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct pxa27x_request *req;
+
+ req = container_of(_req, struct pxa27x_request, req);
+ WARN_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+/**
+ * ep_add_request - add a request to the endpoint's queue
+ * @ep: usb endpoint
+ * @req: usb request
+ *
+ * Context: ep->lock held
+ *
+ * Queues the request in the endpoint's queue, and enables the interrupts
+ * on the endpoint.
+ */
+static void ep_add_request(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ if (unlikely(!req))
+ return;
+ ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
+ req->req.length, udc_ep_readl(ep, UDCCSR));
+
+ req->in_use = 1;
+ list_add_tail(&req->queue, &ep->queue);
+ pio_irq_enable(ep);
+}
+
+/**
+ * ep_del_request - removes a request from the endpoint's queue
+ * @ep: usb endpoint
+ * @req: usb request
+ *
+ * Context: ep->lock held
+ *
+ * Unqueue the request from the endpoint's queue. If there are no more requests
+ * on the endpoint, and if it's not the control endpoint, interrupts are
+ * disabled on the endpoint.
+ */
+static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ if (unlikely(!req))
+ return;
+ ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
+ req->req.length, udc_ep_readl(ep, UDCCSR));
+
+ list_del_init(&req->queue);
+ req->in_use = 0;
+ if (!is_ep0(ep) && list_empty(&ep->queue))
+ pio_irq_disable(ep);
+}
+
+/**
+ * req_done - Complete an usb request
+ * @ep: pxa physical endpoint
+ * @req: pxa request
+ * @status: usb request status sent to gadget API
+ *
+ * Context: ep->lock held
+ *
+ * Retire a pxa27x usb request. Endpoint must be locked.
+ */
+static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
+{
+ ep_del_request(ep, req);
+ if (likely(req->req.status == -EINPROGRESS))
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (status && status != -ESHUTDOWN)
+ ep_dbg(ep, "complete req %p stat %d len %u/%u\n",
+ &req->req, status,
+ req->req.actual, req->req.length);
+
+ req->req.complete(&req->udc_usb_ep->usb_ep, &req->req);
+}
+
+/**
+ * ep_end_out_req - Ends control endpoint in request
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends endpoint in request (completes usb request).
+ */
+static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ inc_ep_stats_reqs(ep, !USB_DIR_IN);
+ req_done(ep, req, 0);
+}
+
+/**
+ * ep0_end_out_req - Ends control endpoint in request (ends data stage)
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends control endpoint in request (completes usb request), and puts
+ * control endpoint into idle state
+ */
+static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ set_ep0state(ep->dev, OUT_STATUS_STAGE);
+ ep_end_out_req(ep, req);
+ ep0_idle(ep->dev);
+}
+
+/**
+ * ep_end_in_req - Ends endpoint out request
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends endpoint out request (completes usb request).
+ */
+static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ inc_ep_stats_reqs(ep, USB_DIR_IN);
+ req_done(ep, req, 0);
+}
+
+/**
+ * ep0_end_in_req - Ends control endpoint out request (ends data stage)
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends control endpoint out request (completes usb request), and puts
+ * control endpoint into status state
+ */
+static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ struct pxa_udc *udc = ep->dev;
+
+ set_ep0state(udc, IN_STATUS_STAGE);
+ ep_end_in_req(ep, req);
+}
+
+/**
+ * nuke - Dequeue all requests
+ * @ep: pxa endpoint
+ * @status: usb request status
+ *
+ * Context: ep->lock held
+ *
+ * Dequeues all requests on an endpoint. As a side effect, interrupts will be
+ * disabled on that endpoint (because no more requests).
+ */
+static void nuke(struct pxa_ep *ep, int status)
+{
+ struct pxa27x_request *req;
+
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct pxa27x_request, queue);
+ req_done(ep, req, status);
+ }
+}
+
+/**
+ * read_packet - transfer 1 packet from an OUT endpoint into request
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ *
+ * Takes bytes from OUT endpoint and transfers them info the usb request.
+ * If there is less space in request than bytes received in OUT endpoint,
+ * bytes are left in the OUT endpoint.
+ *
+ * Returns how many bytes were actually transfered
+ */
+static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ u32 *buf;
+ int bytes_ep, bufferspace, count, i;
+
+ bytes_ep = ep_count_bytes_remain(ep);
+ bufferspace = req->req.length - req->req.actual;
+
+ buf = (u32 *)(req->req.buf + req->req.actual);
+ prefetchw(buf);
+
+ if (likely(!ep_is_empty(ep)))
+ count = min(bytes_ep, bufferspace);
+ else /* zlp */
+ count = 0;
+
+ for (i = count; i > 0; i -= 4)
+ *buf++ = udc_ep_readl(ep, UDCDR);
+ req->req.actual += count;
+
+ udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+
+ return count;
+}
+
+/**
+ * write_packet - transfer 1 packet from request into an IN endpoint
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ * @max: max bytes that fit into endpoint
+ *
+ * Takes bytes from usb request, and transfers them into the physical
+ * endpoint. If there are no bytes to transfer, doesn't write anything
+ * to physical endpoint.
+ *
+ * Returns how many bytes were actually transfered.
+ */
+static int write_packet(struct pxa_ep *ep, struct pxa27x_request *req,
+ unsigned int max)
+{
+ int length, count, remain, i;
+ u32 *buf;
+ u8 *buf_8;
+
+ buf = (u32 *)(req->req.buf + req->req.actual);
+ prefetch(buf);
+
+ length = min(req->req.length - req->req.actual, max);
+ req->req.actual += length;
+
+ remain = length & 0x3;
+ count = length & ~(0x3);
+ for (i = count; i > 0 ; i -= 4)
+ udc_ep_writel(ep, UDCDR, *buf++);
+
+ buf_8 = (u8 *)buf;
+ for (i = remain; i > 0; i--)
+ udc_ep_writeb(ep, UDCDR, *buf_8++);
+
+ ep_vdbg(ep, "length=%d+%d, udccsr=0x%03x\n", count, remain,
+ udc_ep_readl(ep, UDCCSR));
+
+ return length;
+}
+
+/**
+ * read_fifo - Transfer packets from OUT endpoint into usb request
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ *
+ * Context: callable when in_interrupt()
+ *
+ * Unload as many packets as possible from the fifo we use for usb OUT
+ * transfers and put them into the request. Caller should have made sure
+ * there's at least one packet ready.
+ * Doesn't complete the request, that's the caller's job
+ *
+ * Returns 1 if the request completed, 0 otherwise
+ */
+static int read_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ int count, is_short, completed = 0;
+
+ while (epout_has_pkt(ep)) {
+ count = read_packet(ep, req);
+ inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
+
+ is_short = (count < ep->fifo_size);
+ ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
+ udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
+ &req->req, req->req.actual, req->req.length);
+
+ /* completion */
+ if (is_short || req->req.actual == req->req.length) {
+ completed = 1;
+ break;
+ }
+ /* finished that packet. the next one may be waiting... */
+ }
+ return completed;
+}
+
+/**
+ * write_fifo - transfer packets from usb request into an IN endpoint
+ * @ep: pxa physical endpoint
+ * @req: pxa usb request
+ *
+ * Write to an IN endpoint fifo, as many packets as possible.
+ * irqs will use this to write the rest later.
+ * caller guarantees at least one packet buffer is ready (or a zlp).
+ * Doesn't complete the request, that's the caller's job
+ *
+ * Returns 1 if request fully transfered, 0 if partial transfer
+ */
+static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ unsigned max;
+ int count, is_short, is_last = 0, completed = 0, totcount = 0;
+ u32 udccsr;
+
+ max = ep->fifo_size;
+ do {
+ is_short = 0;
+
+ udccsr = udc_ep_readl(ep, UDCCSR);
+ if (udccsr & UDCCSR_PC) {
+ ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n",
+ udccsr);
+ udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+ }
+ if (udccsr & UDCCSR_TRN) {
+ ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n",
+ udccsr);
+ udc_ep_writel(ep, UDCCSR, UDCCSR_TRN);
+ }
+
+ count = write_packet(ep, req, max);
+ inc_ep_stats_bytes(ep, count, USB_DIR_IN);
+ totcount += count;
+
+ /* last packet is usually short (or a zlp) */
+ if (unlikely(count < max)) {
+ is_last = 1;
+ is_short = 1;
+ } else {
+ if (likely(req->req.length > req->req.actual)
+ || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 1;
+ /* interrupt/iso maxpacket may not fill the fifo */
+ is_short = unlikely(max < ep->fifo_size);
+ }
+
+ if (is_short)
+ udc_ep_writel(ep, UDCCSR, UDCCSR_SP);
+
+ /* requests complete when all IN data is in the FIFO */
+ if (is_last) {
+ completed = 1;
+ break;
+ }
+ } while (!ep_is_full(ep));
+
+ ep_dbg(ep, "wrote count:%d bytes%s%s, left:%d req=%p\n",
+ totcount, is_last ? "/L" : "", is_short ? "/S" : "",
+ req->req.length - req->req.actual, &req->req);
+
+ return completed;
+}
+
+/**
+ * read_ep0_fifo - Transfer packets from control endpoint into usb request
+ * @ep: control endpoint
+ * @req: pxa usb request
+ *
+ * Special ep0 version of the above read_fifo. Reads as many bytes from control
+ * endpoint as can be read, and stores them into usb request (limited by request
+ * maximum length).
+ *
+ * Returns 0 if usb request only partially filled, 1 if fully filled
+ */
+static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ int count, is_short, completed = 0;
+
+ while (epout_has_pkt(ep)) {
+ count = read_packet(ep, req);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+ inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
+
+ is_short = (count < ep->fifo_size);
+ ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
+ udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
+ &req->req, req->req.actual, req->req.length);
+
+ if (is_short || req->req.actual >= req->req.length) {
+ completed = 1;
+ break;
+ }
+ }
+
+ return completed;
+}
+
+/**
+ * write_ep0_fifo - Send a request to control endpoint (ep0 in)
+ * @ep: control endpoint
+ * @req: request
+ *
+ * Context: callable when in_interrupt()
+ *
+ * Sends a request (or a part of the request) to the control endpoint (ep0 in).
+ * If the request doesn't fit, the remaining part will be sent from irq.
+ * The request is considered fully written only if either :
+ * - last write transfered all remaining bytes, but fifo was not fully filled
+ * - last write was a 0 length write
+ *
+ * Returns 1 if request fully written, 0 if request only partially sent
+ */
+static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ unsigned count;
+ int is_last, is_short;
+
+ count = write_packet(ep, req, EP0_FIFO_SIZE);
+ inc_ep_stats_bytes(ep, count, USB_DIR_IN);
+
+ is_short = (count < EP0_FIFO_SIZE);
+ is_last = ((count == 0) || (count < EP0_FIFO_SIZE));
+
+ /* Sends either a short packet or a 0 length packet */
+ if (unlikely(is_short))
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_IPR);
+
+ ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n",
+ count, is_short ? "/S" : "", is_last ? "/L" : "",
+ req->req.length - req->req.actual,
+ &req->req, udc_ep_readl(ep, UDCCSR));
+
+ return is_last;
+}
+
+/**
+ * pxa_ep_queue - Queue a request into an IN endpoint
+ * @_ep: usb endpoint
+ * @_req: usb request
+ * @gfp_flags: flags
+ *
+ * Context: normally called when !in_interrupt, but callable when in_interrupt()
+ * in the special case of ep0 setup :
+ * (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue)
+ *
+ * Returns 0 if succedeed, error otherwise
+ */
+static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct udc_usb_ep *udc_usb_ep;
+ struct pxa_ep *ep;
+ struct pxa27x_request *req;
+ struct pxa_udc *dev;
+ unsigned long flags;
+ int rc = 0;
+ int is_first_req;
+ unsigned length;
+
+ req = container_of(_req, struct pxa27x_request, req);
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+
+ if (unlikely(!_req || !_req->complete || !_req->buf))
+ return -EINVAL;
+
+ if (unlikely(!_ep))
+ return -EINVAL;
+
+ dev = udc_usb_ep->dev;
+ ep = udc_usb_ep->pxa_ep;
+ if (unlikely(!ep))
+ return -EINVAL;
+
+ dev = ep->dev;
+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+ ep_dbg(ep, "bogus device state\n");
+ return -ESHUTDOWN;
+ }
+
+ /* iso is always one packet per request, that's the only way
+ * we can report per-packet status. that also helps with dma.
+ */
+ if (unlikely(EPXFERTYPE_is_ISO(ep)
+ && req->req.length > ep->fifo_size))
+ return -EMSGSIZE;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ is_first_req = list_empty(&ep->queue);
+ ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n",
+ _req, is_first_req ? "yes" : "no",
+ _req->length, _req->buf);
+
+ if (!ep->enabled) {
+ _req->status = -ESHUTDOWN;
+ rc = -ESHUTDOWN;
+ goto out;
+ }
+
+ if (req->in_use) {
+ ep_err(ep, "refusing to queue req %p (already queued)\n", req);
+ goto out;
+ }
+
+ length = _req->length;
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ ep_add_request(ep, req);
+
+ if (is_ep0(ep)) {
+ switch (dev->ep0state) {
+ case WAIT_ACK_SET_CONF_INTERF:
+ if (length == 0) {
+ ep_end_in_req(ep, req);
+ } else {
+ ep_err(ep, "got a request of %d bytes while"
+ "in state WATI_ACK_SET_CONF_INTERF\n",
+ length);
+ ep_del_request(ep, req);
+ rc = -EL2HLT;
+ }
+ ep0_idle(ep->dev);
+ break;
+ case IN_DATA_STAGE:
+ if (!ep_is_full(ep))
+ if (write_ep0_fifo(ep, req))
+ ep0_end_in_req(ep, req);
+ break;
+ case OUT_DATA_STAGE:
+ if ((length == 0) || !epout_has_pkt(ep))
+ if (read_ep0_fifo(ep, req))
+ ep0_end_out_req(ep, req);
+ break;
+ default:
+ ep_err(ep, "odd state %s to send me a request\n",
+ EP0_STNAME(ep->dev));
+ ep_del_request(ep, req);
+ rc = -EL2HLT;
+ break;
+ }
+ } else {
+ handle_ep(ep);
+ }
+
+out:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ return rc;
+}
+
+/**
+ * pxa_ep_dequeue - Dequeue one request
+ * @_ep: usb endpoint
+ * @_req: usb request
+ *
+ * Return 0 if no error, -EINVAL or -ECONNRESET otherwise
+ */
+static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ struct pxa27x_request *req;
+ unsigned long flags;
+ int rc;
+
+ if (!_ep)
+ return -EINVAL;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+
+ rc = -EINVAL;
+ if (&req->req != _req)
+ goto out;
+
+ rc = 0;
+ req_done(ep, req, -ECONNRESET);
+out:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ return rc;
+}
+
+/**
+ * pxa_ep_set_halt - Halts operations on one endpoint
+ * @_ep: usb endpoint
+ * @value:
+ *
+ * Returns 0 if no error, -EINVAL, -EROFS, -EAGAIN otherwise
+ */
+static int pxa_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned long flags;
+ int rc;
+
+
+ if (!_ep)
+ return -EINVAL;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return -EINVAL;
+
+ if (value == 0) {
+ /*
+ * This path (reset toggle+halt) is needed to implement
+ * SET_INTERFACE on normal hardware. but it can't be
+ * done from software on the PXA UDC, and the hardware
+ * forgets to do it as part of SET_INTERFACE automagic.
+ */
+ ep_dbg(ep, "only host can clear halt\n");
+ return -EROFS;
+ }
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ rc = -EAGAIN;
+ if (ep->dir_in && (ep_is_full(ep) || !list_empty(&ep->queue)))
+ goto out;
+
+ /* FST, FEF bits are the same for control and non control endpoints */
+ rc = 0;
+ udc_ep_writel(ep, UDCCSR, UDCCSR_FST | UDCCSR_FEF);
+ if (is_ep0(ep))
+ set_ep0state(ep->dev, STALL);
+
+out:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ return rc;
+}
+
+/**
+ * pxa_ep_fifo_status - Get how many bytes in physical endpoint
+ * @_ep: usb endpoint
+ *
+ * Returns number of bytes in OUT fifos. Broken for IN fifos.
+ */
+static int pxa_ep_fifo_status(struct usb_ep *_ep)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+
+ if (!_ep)
+ return -ENODEV;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return -ENODEV;
+
+ if (ep->dir_in)
+ return -EOPNOTSUPP;
+ if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN || ep_is_empty(ep))
+ return 0;
+ else
+ return ep_count_bytes_remain(ep) + 1;
+}
+
+/**
+ * pxa_ep_fifo_flush - Flushes one endpoint
+ * @_ep: usb endpoint
+ *
+ * Discards all data in one endpoint(IN or OUT), except control endpoint.
+ */
+static void pxa_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned long flags;
+
+ if (!_ep)
+ return;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ if (unlikely(!list_empty(&ep->queue)))
+ ep_dbg(ep, "called while queue list not empty\n");
+ ep_dbg(ep, "called\n");
+
+ /* for OUT, just read and discard the FIFO contents. */
+ if (!ep->dir_in) {
+ while (!ep_is_empty(ep))
+ udc_ep_readl(ep, UDCDR);
+ } else {
+ /* most IN status is the same, but ISO can't stall */
+ udc_ep_writel(ep, UDCCSR,
+ UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN
+ | (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST));
+ }
+
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ return;
+}
+
+/**
+ * pxa_ep_enable - Enables usb endpoint
+ * @_ep: usb endpoint
+ * @desc: usb endpoint descriptor
+ *
+ * Nothing much to do here, as ep configuration is done once and for all
+ * before udc is enabled. After udc enable, no physical endpoint configuration
+ * can be changed.
+ * Function makes sanity checks and flushes the endpoint.
+ */
+static int pxa_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ struct pxa_udc *udc;
+
+ if (!_ep || !desc)
+ return -EINVAL;
+
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ if (udc_usb_ep->pxa_ep) {
+ ep = udc_usb_ep->pxa_ep;
+ ep_warn(ep, "usb_ep %s already enabled, doing nothing\n",
+ _ep->name);
+ } else {
+ ep = find_pxa_ep(udc_usb_ep->dev, udc_usb_ep);
+ }
+
+ if (!ep || is_ep0(ep)) {
+ dev_err(udc_usb_ep->dev->dev,
+ "unable to match pxa_ep for ep %s\n",
+ _ep->name);
+ return -EINVAL;
+ }
+
+ if ((desc->bDescriptorType != USB_DT_ENDPOINT)
+ || (ep->type != usb_endpoint_type(desc))) {
+ ep_err(ep, "type mismatch\n");
+ return -EINVAL;
+ }
+
+ if (ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) {
+ ep_err(ep, "bad maxpacket\n");
+ return -ERANGE;
+ }
+
+ udc_usb_ep->pxa_ep = ep;
+ udc = ep->dev;
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+ ep_err(ep, "bogus device state\n");
+ return -ESHUTDOWN;
+ }
+
+ ep->enabled = 1;
+
+ /* flush fifo (mostly for OUT buffers) */
+ pxa_ep_fifo_flush(_ep);
+
+ ep_dbg(ep, "enabled\n");
+ return 0;
+}
+
+/**
+ * pxa_ep_disable - Disable usb endpoint
+ * @_ep: usb endpoint
+ *
+ * Same as for pxa_ep_enable, no physical endpoint configuration can be
+ * changed.
+ * Function flushes the endpoint and related requests.
+ */
+static int pxa_ep_disable(struct usb_ep *_ep)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned long flags;
+
+ if (!_ep)
+ return -EINVAL;
+
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ ep->enabled = 0;
+ nuke(ep, -ESHUTDOWN);
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ pxa_ep_fifo_flush(_ep);
+ udc_usb_ep->pxa_ep = NULL;
+
+ ep_dbg(ep, "disabled\n");
+ return 0;
+}
+
+static struct usb_ep_ops pxa_ep_ops = {
+ .enable = pxa_ep_enable,
+ .disable = pxa_ep_disable,
+
+ .alloc_request = pxa_ep_alloc_request,
+ .free_request = pxa_ep_free_request,
+
+ .queue = pxa_ep_queue,
+ .dequeue = pxa_ep_dequeue,
+
+ .set_halt = pxa_ep_set_halt,
+ .fifo_status = pxa_ep_fifo_status,
+ .fifo_flush = pxa_ep_fifo_flush,
+};
+
+
+/**
+ * pxa_udc_get_frame - Returns usb frame number
+ * @_gadget: usb gadget
+ */
+static int pxa_udc_get_frame(struct usb_gadget *_gadget)
+{
+ struct pxa_udc *udc = to_gadget_udc(_gadget);
+
+ return (udc_readl(udc, UDCFNR) & 0x7ff);
+}
+
+/**
+ * pxa_udc_wakeup - Force udc device out of suspend
+ * @_gadget: usb gadget
+ *
+ * Returns 0 if succesfull, error code otherwise
+ */
+static int pxa_udc_wakeup(struct usb_gadget *_gadget)
+{
+ struct pxa_udc *udc = to_gadget_udc(_gadget);
+
+ /* host may not have enabled remote wakeup */
+ if ((udc_readl(udc, UDCCR) & UDCCR_DWRE) == 0)
+ return -EHOSTUNREACH;
+ udc_set_mask_UDCCR(udc, UDCCR_UDR);
+ return 0;
+}
+
+static const struct usb_gadget_ops pxa_udc_ops = {
+ .get_frame = pxa_udc_get_frame,
+ .wakeup = pxa_udc_wakeup,
+ /* current versions must always be self-powered */
+};
+
+/**
+ * udc_disable - disable udc device controller
+ * @udc: udc device
+ *
+ * Disables the udc device : disables clocks, udc interrupts, control endpoint
+ * interrupts.
+ */
+static void udc_disable(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCICR0, 0);
+ udc_writel(udc, UDCICR1, 0);
+
+ udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+ clk_disable(udc->clk);
+
+ ep0_idle(udc);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+}
+
+/**
+ * udc_init_data - Initialize udc device data structures
+ * @dev: udc device
+ *
+ * Initializes gadget endpoint list, endpoints locks. No action is taken
+ * on the hardware.
+ */
+static __init void udc_init_data(struct pxa_udc *dev)
+{
+ int i;
+ struct pxa_ep *ep;
+
+ /* device/ep0 records init */
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+ dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0];
+ ep0_idle(dev);
+ strcpy(dev->dev->bus_id, "");
+
+ /* PXA endpoints init */
+ for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &dev->pxa_ep[i];
+
+ ep->enabled = is_ep0(ep);
+ INIT_LIST_HEAD(&ep->queue);
+ spin_lock_init(&ep->lock);
+ }
+
+ /* USB endpoints init */
+ for (i = 0; i < NR_USB_ENDPOINTS; i++)
+ if (i != 0)
+ list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,
+ &dev->gadget.ep_list);
+}
+
+/**
+ * udc_enable - Enables the udc device
+ * @dev: udc device
+ *
+ * Enables the udc device : enables clocks, udc interrupts, control endpoint
+ * interrupts, sets usb as UDC client and setups endpoints.
+ */
+static void udc_enable(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCICR0, 0);
+ udc_writel(udc, UDCICR1, 0);
+ udc_writel(udc, UP2OCR, UP2OCR_HXOE);
+ udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+
+ clk_enable(udc->clk);
+
+ ep0_idle(udc);
+ udc->gadget.speed = USB_SPEED_FULL;
+ memset(&udc->stats, 0, sizeof(udc->stats));
+
+ udc_set_mask_UDCCR(udc, UDCCR_UDE);
+ udelay(2);
+ if (udc_readl(udc, UDCCR) & UDCCR_EMCE)
+ dev_err(udc->dev, "Configuration errors, udc disabled\n");
+
+ /*
+ * Caller must be able to sleep in order to cope with startup transients
+ */
+ msleep(100);
+
+ /* enable suspend/resume and reset irqs */
+ udc_writel(udc, UDCICR1,
+ UDCICR1_IECC | UDCICR1_IERU
+ | UDCICR1_IESU | UDCICR1_IERS);
+
+ /* enable ep0 irqs */
+ pio_irq_enable(&udc->pxa_ep[0]);
+
+ dev_info(udc->dev, "UDC connecting\n");
+ if (udc->mach->udc_command)
+ udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+}
+
+/**
+ * usb_gadget_register_driver - Register gadget driver
+ * @driver: gadget driver
+ *
+ * When a driver is successfully registered, it will receive control requests
+ * including set_configuration(), which enables non-control requests. Then
+ * usb traffic follows until a disconnect is reported. Then a host may connect
+ * again, or the driver might get unbound.
+ *
+ * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct pxa_udc *udc = the_controller;
+ int retval;
+
+ if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind
+ || !driver->disconnect || !driver->setup)
+ return -EINVAL;
+ if (!udc)
+ return -ENODEV;
+ if (udc->driver)
+ return -EBUSY;
+
+ /* first hook up the driver ... */
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+
+ retval = device_add(&udc->gadget.dev);
+ if (retval) {
+ dev_err(udc->dev, "device_add error %d\n", retval);
+ goto add_fail;
+ }
+ retval = driver->bind(&udc->gadget);
+ if (retval) {
+ dev_err(udc->dev, "bind to driver %s --> error %d\n",
+ driver->driver.name, retval);
+ goto bind_fail;
+ }
+ dev_dbg(udc->dev, "registered gadget driver '%s'\n",
+ driver->driver.name);
+
+ udc_enable(udc);
+ return 0;
+
+bind_fail:
+ device_del(&udc->gadget.dev);
+add_fail:
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+
+/**
+ * stop_activity - Stops udc endpoints
+ * @udc: udc device
+ * @driver: gadget driver
+ *
+ * Disables all udc endpoints (even control endpoint), report disconnect to
+ * the gadget user.
+ */
+static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
+{
+ int i;
+
+ /* don't disconnect drivers more than once */
+ if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+ for (i = 0; i < NR_USB_ENDPOINTS; i++)
+ pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep);
+
+ if (driver)
+ driver->disconnect(&udc->gadget);
+}
+
+/**
+ * usb_gadget_unregister_driver - Unregister the gadget driver
+ * @driver: gadget driver
+ *
+ * Returns 0 if no error, -ENODEV, -EINVAL otherwise
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct pxa_udc *udc = the_controller;
+
+ if (!udc)
+ return -ENODEV;
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ stop_activity(udc, driver);
+ udc_disable(udc);
+
+ driver->unbind(&udc->gadget);
+ udc->driver = NULL;
+
+ device_del(&udc->gadget.dev);
+
+ dev_info(udc->dev, "unregistered gadget driver '%s'\n",
+ driver->driver.name);
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/**
+ * handle_ep0_ctrl_req - handle control endpoint control request
+ * @udc: udc device
+ * @req: control request
+ */
+static void handle_ep0_ctrl_req(struct pxa_udc *udc,
+ struct pxa27x_request *req)
+{
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+ union {
+ struct usb_ctrlrequest r;
+ u32 word[2];
+ } u;
+ int i;
+ int have_extrabytes = 0;
+
+ nuke(ep, -EPROTO);
+
+ /* read SETUP packet */
+ for (i = 0; i < 2; i++) {
+ if (unlikely(ep_is_empty(ep)))
+ goto stall;
+ u.word[i] = udc_ep_readl(ep, UDCDR);
+ }
+
+ have_extrabytes = !ep_is_empty(ep);
+ while (!ep_is_empty(ep)) {
+ i = udc_ep_readl(ep, UDCDR);
+ ep_err(ep, "wrong to have extra bytes for setup : 0x%08x\n", i);
+ }
+
+ le16_to_cpus(&u.r.wValue);
+ le16_to_cpus(&u.r.wIndex);
+ le16_to_cpus(&u.r.wLength);
+
+ ep_dbg(ep, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+ u.r.bRequestType, u.r.bRequest,
+ u.r.wValue, u.r.wIndex, u.r.wLength);
+ if (unlikely(have_extrabytes))
+ goto stall;
+
+ if (u.r.bRequestType & USB_DIR_IN)
+ set_ep0state(udc, IN_DATA_STAGE);
+ else
+ set_ep0state(udc, OUT_DATA_STAGE);
+
+ /* Tell UDC to enter Data Stage */
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_SA | UDCCSR0_OPC);
+
+ i = udc->driver->setup(&udc->gadget, &u.r);
+ if (i < 0)
+ goto stall;
+out:
+ return;
+stall:
+ ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
+ udc_ep_readl(ep, UDCCSR), i);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_FST | UDCCSR0_FTF);
+ set_ep0state(udc, STALL);
+ goto out;
+}
+
+/**
+ * handle_ep0 - Handle control endpoint data transfers
+ * @udc: udc device
+ * @fifo_irq: 1 if triggered by fifo service type irq
+ * @opc_irq: 1 if triggered by output packet complete type irq
+ *
+ * Context : when in_interrupt() or with ep->lock held
+ *
+ * Tries to transfer all pending request data into the endpoint and/or
+ * transfer all pending data in the endpoint into usb requests.
+ * Handles states of ep0 automata.
+ *
+ * PXA27x hardware handles several standard usb control requests without
+ * driver notification. The requests fully handled by hardware are :
+ * SET_ADDRESS, SET_FEATURE, CLEAR_FEATURE, GET_CONFIGURATION, GET_INTERFACE,
+ * GET_STATUS
+ * The requests handled by hardware, but with irq notification are :
+ * SYNCH_FRAME, SET_CONFIGURATION, SET_INTERFACE
+ * The remaining standard requests really handled by handle_ep0 are :
+ * GET_DESCRIPTOR, SET_DESCRIPTOR, specific requests.
+ * Requests standardized outside of USB 2.0 chapter 9 are handled more
+ * uniformly, by gadget drivers.
+ *
+ * The control endpoint state machine is _not_ USB spec compliant, it's even
+ * hardly compliant with Intel PXA270 developers guide.
+ * The key points which inferred this state machine are :
+ * - on every setup token, bit UDCCSR0_SA is raised and held until cleared by
+ * software.
+ * - on every OUT packet received, UDCCSR0_OPC is raised and held until
+ * cleared by software.
+ * - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it
+ * before reading ep0.
+ * - irq can be called on a "packet complete" event (opc_irq=1), while
+ * UDCCSR0_OPC is not yet raised (delta can be as big as 100ms
+ * from experimentation).
+ * - as UDCCSR0_SA can be activated while in irq handling, and clearing
+ * UDCCSR0_OPC would flush the setup data, we almost never clear UDCCSR0_OPC
+ * => we never actually read the "status stage" packet of an IN data stage
+ * => this is not documented in Intel documentation
+ * - hardware as no idea of STATUS STAGE, it only handle SETUP STAGE and DATA
+ * STAGE. The driver add STATUS STAGE to send last zero length packet in
+ * OUT_STATUS_STAGE.
+ * - special attention was needed for IN_STATUS_STAGE. If a packet complete
+ * event is detected, we terminate the status stage without ackowledging the
+ * packet (not to risk to loose a potential SETUP packet)
+ */
+static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
+{
+ u32 udccsr0;
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+ struct pxa27x_request *req = NULL;
+ int completed = 0;
+
+ udccsr0 = udc_ep_readl(ep, UDCCSR);
+ ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n",
+ EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR),
+ (fifo_irq << 1 | opc_irq));
+
+ if (!list_empty(&ep->queue))
+ req = list_entry(ep->queue.next, struct pxa27x_request, queue);
+
+ if (udccsr0 & UDCCSR0_SST) {
+ ep_dbg(ep, "clearing stall status\n");
+ nuke(ep, -EPIPE);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_SST);
+ ep0_idle(udc);
+ }
+
+ if (udccsr0 & UDCCSR0_SA) {
+ nuke(ep, 0);
+ set_ep0state(udc, SETUP_STAGE);
+ }
+
+ switch (udc->ep0state) {
+ case WAIT_FOR_SETUP:
+ /*
+ * Hardware bug : beware, we cannot clear OPC, since we would
+ * miss a potential OPC irq for a setup packet.
+ * So, we only do ... nothing, and hope for a next irq with
+ * UDCCSR0_SA set.
+ */
+ break;
+ case SETUP_STAGE:
+ udccsr0 &= UDCCSR0_CTRL_REQ_MASK;
+ if (likely(udccsr0 == UDCCSR0_CTRL_REQ_MASK))
+ handle_ep0_ctrl_req(udc, req);
+ break;
+ case IN_DATA_STAGE: /* GET_DESCRIPTOR */
+ if (epout_has_pkt(ep))
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+ if (req && !ep_is_full(ep))
+ completed = write_ep0_fifo(ep, req);
+ if (completed)
+ ep0_end_in_req(ep, req);
+ break;
+ case OUT_DATA_STAGE: /* SET_DESCRIPTOR */
+ if (epout_has_pkt(ep) && req)
+ completed = read_ep0_fifo(ep, req);
+ if (completed)
+ ep0_end_out_req(ep, req);
+ break;
+ case STALL:
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_FST);
+ break;
+ case IN_STATUS_STAGE:
+ /*
+ * Hardware bug : beware, we cannot clear OPC, since we would
+ * miss a potential PC irq for a setup packet.
+ * So, we only put the ep0 into WAIT_FOR_SETUP state.
+ */
+ if (opc_irq)
+ ep0_idle(udc);
+ break;
+ case OUT_STATUS_STAGE:
+ case WAIT_ACK_SET_CONF_INTERF:
+ ep_warn(ep, "should never get in %s state here!!!\n",
+ EP0_STNAME(ep->dev));
+ ep0_idle(udc);
+ break;
+ }
+}
+
+/**
+ * handle_ep - Handle endpoint data tranfers
+ * @ep: pxa physical endpoint
+ *
+ * Tries to transfer all pending request data into the endpoint and/or
+ * transfer all pending data in the endpoint into usb requests.
+ *
+ * Is always called when in_interrupt() or with ep->lock held.
+ */
+static void handle_ep(struct pxa_ep *ep)
+{
+ struct pxa27x_request *req;
+ int completed;
+ u32 udccsr;
+ int is_in = ep->dir_in;
+ int loop = 0;
+
+ do {
+ completed = 0;
+ udccsr = udc_ep_readl(ep, UDCCSR);
+ if (likely(!list_empty(&ep->queue)))
+ req = list_entry(ep->queue.next,
+ struct pxa27x_request, queue);
+ else
+ req = NULL;
+
+ ep_dbg(ep, "req:%p, udccsr 0x%03x loop=%d\n",
+ req, udccsr, loop++);
+
+ if (unlikely(udccsr & (UDCCSR_SST | UDCCSR_TRN)))
+ udc_ep_writel(ep, UDCCSR,
+ udccsr & (UDCCSR_SST | UDCCSR_TRN));
+ if (!req)
+ break;
+
+ if (unlikely(is_in)) {
+ if (likely(!ep_is_full(ep)))
+ completed = write_fifo(ep, req);
+ if (completed)
+ ep_end_in_req(ep, req);
+ } else {
+ if (likely(epout_has_pkt(ep)))
+ completed = read_fifo(ep, req);
+ if (completed)
+ ep_end_out_req(ep, req);
+ }
+ } while (completed);
+}
+
+/**
+ * pxa27x_change_configuration - Handle SET_CONF usb request notification
+ * @udc: udc device
+ * @config: usb configuration
+ *
+ * Post the request to upper level.
+ * Don't use any pxa specific harware configuration capabilities
+ */
+static void pxa27x_change_configuration(struct pxa_udc *udc, int config)
+{
+ struct usb_ctrlrequest req ;
+
+ dev_dbg(udc->dev, "config=%d\n", config);
+
+ udc->config = config;
+ udc->last_interface = 0;
+ udc->last_alternate = 0;
+
+ req.bRequestType = 0;
+ req.bRequest = USB_REQ_SET_CONFIGURATION;
+ req.wValue = config;
+ req.wIndex = 0;
+ req.wLength = 0;
+
+ set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
+ udc->driver->setup(&udc->gadget, &req);
+}
+
+/**
+ * pxa27x_change_interface - Handle SET_INTERF usb request notification
+ * @udc: udc device
+ * @iface: interface number
+ * @alt: alternate setting number
+ *
+ * Post the request to upper level.
+ * Don't use any pxa specific harware configuration capabilities
+ */
+static void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt)
+{
+ struct usb_ctrlrequest req;
+
+ dev_dbg(udc->dev, "interface=%d, alternate setting=%d\n", iface, alt);
+
+ udc->last_interface = iface;
+ udc->last_alternate = alt;
+
+ req.bRequestType = USB_RECIP_INTERFACE;
+ req.bRequest = USB_REQ_SET_INTERFACE;
+ req.wValue = alt;
+ req.wIndex = iface;
+ req.wLength = 0;
+
+ set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
+ udc->driver->setup(&udc->gadget, &req);
+}
+
+/*
+ * irq_handle_data - Handle data transfer
+ * @irq: irq IRQ number
+ * @udc: dev pxa_udc device structure
+ *
+ * Called from irq handler, transferts data to or from endpoint to queue
+ */
+static void irq_handle_data(int irq, struct pxa_udc *udc)
+{
+ int i;
+ struct pxa_ep *ep;
+ u32 udcisr0 = udc_readl(udc, UDCISR0) & UDCCISR0_EP_MASK;
+ u32 udcisr1 = udc_readl(udc, UDCISR1) & UDCCISR1_EP_MASK;
+
+ if (udcisr0 & UDCISR_INT_MASK) {
+ udc->pxa_ep[0].stats.irqs++;
+ udc_writel(udc, UDCISR0, UDCISR_INT(0, UDCISR_INT_MASK));
+ handle_ep0(udc, !!(udcisr0 & UDCICR_FIFOERR),
+ !!(udcisr0 & UDCICR_PKTCOMPL));
+ }
+
+ udcisr0 >>= 2;
+ for (i = 1; udcisr0 != 0 && i < 16; udcisr0 >>= 2, i++) {
+ if (!(udcisr0 & UDCISR_INT_MASK))
+ continue;
+
+ udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK));
+ ep = &udc->pxa_ep[i];
+ ep->stats.irqs++;
+ handle_ep(ep);
+ }
+
+ for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) {
+ udc_writel(udc, UDCISR1, UDCISR_INT(i - 16, UDCISR_INT_MASK));
+ if (!(udcisr1 & UDCISR_INT_MASK))
+ continue;
+
+ ep = &udc->pxa_ep[i];
+ ep->stats.irqs++;
+ handle_ep(ep);
+ }
+
+}
+
+/**
+ * irq_udc_suspend - Handle IRQ "UDC Suspend"
+ * @udc: udc device
+ */
+static void irq_udc_suspend(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCISR1, UDCISR1_IRSU);
+ udc->stats.irqs_suspend++;
+
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+ ep0_idle(udc);
+}
+
+/**
+ * irq_udc_resume - Handle IRQ "UDC Resume"
+ * @udc: udc device
+ */
+static void irq_udc_resume(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCISR1, UDCISR1_IRRU);
+ udc->stats.irqs_resume++;
+
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->resume)
+ udc->driver->resume(&udc->gadget);
+}
+
+/**
+ * irq_udc_reconfig - Handle IRQ "UDC Change Configuration"
+ * @udc: udc device
+ */
+static void irq_udc_reconfig(struct pxa_udc *udc)
+{
+ unsigned config, interface, alternate, config_change;
+ u32 udccr = udc_readl(udc, UDCCR);
+
+ udc_writel(udc, UDCISR1, UDCISR1_IRCC);
+ udc->stats.irqs_reconfig++;
+
+ config = (udccr & UDCCR_ACN) >> UDCCR_ACN_S;
+ config_change = (config != udc->config);
+ pxa27x_change_configuration(udc, config);
+
+ interface = (udccr & UDCCR_AIN) >> UDCCR_AIN_S;
+ alternate = (udccr & UDCCR_AAISN) >> UDCCR_AAISN_S;
+ pxa27x_change_interface(udc, interface, alternate);
+
+ if (config_change)
+ update_pxa_ep_matches(udc);
+ udc_set_mask_UDCCR(udc, UDCCR_SMAC);
+}
+
+/**
+ * irq_udc_reset - Handle IRQ "UDC Reset"
+ * @udc: udc device
+ */
+static void irq_udc_reset(struct pxa_udc *udc)
+{
+ u32 udccr = udc_readl(udc, UDCCR);
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+
+ dev_info(udc->dev, "USB reset\n");
+ udc_writel(udc, UDCISR1, UDCISR1_IRRS);
+ udc->stats.irqs_reset++;
+
+ if ((udccr & UDCCR_UDA) == 0) {
+ dev_dbg(udc->dev, "USB reset start\n");
+ stop_activity(udc, udc->driver);
+ }
+ udc->gadget.speed = USB_SPEED_FULL;
+ memset(&udc->stats, 0, sizeof udc->stats);
+
+ nuke(ep, -EPROTO);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_FTF | UDCCSR0_OPC);
+ ep0_idle(udc);
+}
+
+/**
+ * pxa_udc_irq - Main irq handler
+ * @irq: irq number
+ * @_dev: udc device
+ *
+ * Handles all udc interrupts
+ */
+static irqreturn_t pxa_udc_irq(int irq, void *_dev)
+{
+ struct pxa_udc *udc = _dev;
+ u32 udcisr0 = udc_readl(udc, UDCISR0);
+ u32 udcisr1 = udc_readl(udc, UDCISR1);
+ u32 udccr = udc_readl(udc, UDCCR);
+ u32 udcisr1_spec;
+
+ dev_vdbg(udc->dev, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, "
+ "UDCCR:0x%08x\n", udcisr0, udcisr1, udccr);
+
+ udcisr1_spec = udcisr1 & 0xf8000000;
+ if (unlikely(udcisr1_spec & UDCISR1_IRSU))
+ irq_udc_suspend(udc);
+ if (unlikely(udcisr1_spec & UDCISR1_IRRU))
+ irq_udc_resume(udc);
+ if (unlikely(udcisr1_spec & UDCISR1_IRCC))
+ irq_udc_reconfig(udc);
+ if (unlikely(udcisr1_spec & UDCISR1_IRRS))
+ irq_udc_reset(udc);
+
+ if ((udcisr0 & UDCCISR0_EP_MASK) | (udcisr1 & UDCCISR1_EP_MASK))
+ irq_handle_data(irq, udc);
+
+ return IRQ_HANDLED;
+}
+
+static struct pxa_udc memory = {
+ .gadget = {
+ .ops = &pxa_udc_ops,
+ .ep0 = &memory.udc_usb_ep[0].usb_ep,
+ .name = driver_name,
+ .dev = {
+ .bus_id = "gadget",
+ },
+ },
+
+ .udc_usb_ep = {
+ USB_EP_CTRL,
+ USB_EP_OUT_BULK(1),
+ USB_EP_IN_BULK(2),
+ USB_EP_IN_ISO(3),
+ USB_EP_OUT_ISO(4),
+ USB_EP_IN_INT(5),
+ },
+
+ .pxa_ep = {
+ PXA_EP_CTRL,
+ /* Endpoints for gadget zero */
+ PXA_EP_OUT_BULK(1, 1, 3, 0, 0),
+ PXA_EP_IN_BULK(2, 2, 3, 0, 0),
+ /* Endpoints for ether gadget, file storage gadget */
+ PXA_EP_OUT_BULK(3, 1, 1, 0, 0),
+ PXA_EP_IN_BULK(4, 2, 1, 0, 0),
+ PXA_EP_IN_ISO(5, 3, 1, 0, 0),
+ PXA_EP_OUT_ISO(6, 4, 1, 0, 0),
+ PXA_EP_IN_INT(7, 5, 1, 0, 0),
+ /* Endpoints for RNDIS, serial */
+ PXA_EP_OUT_BULK(8, 1, 2, 0, 0),
+ PXA_EP_IN_BULK(9, 2, 2, 0, 0),
+ PXA_EP_IN_INT(10, 5, 2, 0, 0),
+ /*
+ * All the following endpoints are only for completion. They
+ * won't never work, as multiple interfaces are really broken on
+ * the pxa.
+ */
+ PXA_EP_OUT_BULK(11, 1, 2, 1, 0),
+ PXA_EP_IN_BULK(12, 2, 2, 1, 0),
+ /* Endpoint for CDC Ether */
+ PXA_EP_OUT_BULK(13, 1, 1, 1, 1),
+ PXA_EP_IN_BULK(14, 2, 1, 1, 1),
+ }
+};
+
+/**
+ * pxa_udc_probe - probes the udc device
+ * @_dev: platform device
+ *
+ * Perform basic init : allocates udc clock, creates sysfs files, requests
+ * irq.
+ */
+static int __init pxa_udc_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ struct pxa_udc *udc = &memory;
+ int retval;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+ udc->irq = platform_get_irq(pdev, 0);
+ if (udc->irq < 0)
+ return udc->irq;
+
+ udc->dev = &pdev->dev;
+ udc->mach = pdev->dev.platform_data;
+
+ udc->clk = clk_get(&pdev->dev, "UDCCLK");
+ if (IS_ERR(udc->clk)) {
+ retval = PTR_ERR(udc->clk);
+ goto err_clk;
+ }
+
+ retval = -ENOMEM;
+ udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!udc->regs) {
+ dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
+ goto err_map;
+ }
+
+ device_initialize(&udc->gadget.dev);
+ udc->gadget.dev.parent = &pdev->dev;
+ udc->gadget.dev.dma_mask = NULL;
+
+ the_controller = udc;
+ platform_set_drvdata(pdev, udc);
+ udc_init_data(udc);
+ pxa_eps_setup(udc);
+
+ /* irq setup after old hardware state is cleaned up */
+ retval = request_irq(udc->irq, pxa_udc_irq,
+ IRQF_SHARED, driver_name, udc);
+ if (retval != 0) {
+ dev_err(udc->dev, "%s: can't get irq %i, err %d\n",
+ driver_name, IRQ_USB, retval);
+ goto err_irq;
+ }
+
+ pxa_init_debugfs(udc);
+ return 0;
+err_irq:
+ iounmap(udc->regs);
+err_map:
+ clk_put(udc->clk);
+ udc->clk = NULL;
+err_clk:
+ return retval;
+}
+
+/**
+ * pxa_udc_remove - removes the udc device driver
+ * @_dev: platform device
+ */
+static int __exit pxa_udc_remove(struct platform_device *_dev)
+{
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+
+ usb_gadget_unregister_driver(udc->driver);
+ free_irq(udc->irq, udc);
+ pxa_cleanup_debugfs(udc);
+
+ platform_set_drvdata(_dev, NULL);
+ the_controller = NULL;
+ clk_put(udc->clk);
+
+ return 0;
+}
+
+static void pxa_udc_shutdown(struct platform_device *_dev)
+{
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+
+ udc_disable(udc);
+}
+
+#ifdef CONFIG_PM
+/**
+ * pxa_udc_suspend - Suspend udc device
+ * @_dev: platform device
+ * @state: suspend state
+ *
+ * Suspends udc : saves configuration registers (UDCCR*), then disables the udc
+ * device.
+ */
+static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
+{
+ int i;
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+ struct pxa_ep *ep;
+
+ ep = &udc->pxa_ep[0];
+ udc->udccsr0 = udc_ep_readl(ep, UDCCSR);
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ ep->udccsr_value = udc_ep_readl(ep, UDCCSR);
+ ep->udccr_value = udc_ep_readl(ep, UDCCR);
+ ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
+ ep->udccsr_value, ep->udccr_value);
+ }
+
+ udc_disable(udc);
+
+ return 0;
+}
+
+/**
+ * pxa_udc_resume - Resume udc device
+ * @_dev: platform device
+ *
+ * Resumes udc : restores configuration registers (UDCCR*), then enables the udc
+ * device.
+ */
+static int pxa_udc_resume(struct platform_device *_dev)
+{
+ int i;
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+ struct pxa_ep *ep;
+
+ ep = &udc->pxa_ep[0];
+ udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME));
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ udc_ep_writel(ep, UDCCSR, ep->udccsr_value);
+ udc_ep_writel(ep, UDCCR, ep->udccr_value);
+ ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
+ ep->udccsr_value, ep->udccr_value);
+ }
+
+ udc_enable(udc);
+ /*
+ * We do not handle OTG yet.
+ *
+ * OTGPH bit is set when sleep mode is entered.
+ * it indicates that OTG pad is retaining its state.
+ * Upon exit from sleep mode and before clearing OTGPH,
+ * Software must configure the USB OTG pad, UDC, and UHC
+ * to the state they were in before entering sleep mode.
+ *
+ * Should be : PSSR |= PSSR_OTGPH;
+ */
+
+ return 0;
+}
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:pxa2xx-udc");
+
+static struct platform_driver udc_driver = {
+ .driver = {
+ .name = "pxa2xx-udc",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(pxa_udc_remove),
+ .shutdown = pxa_udc_shutdown,
+#ifdef CONFIG_PM
+ .suspend = pxa_udc_suspend,
+ .resume = pxa_udc_resume
+#endif
+};
+
+static int __init udc_init(void)
+{
+ printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
+ return platform_driver_probe(&udc_driver, pxa_udc_probe);
+}
+module_init(udc_init);
+
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
new file mode 100644
index 00000000000..1d1b7936ee1
--- /dev/null
+++ b/drivers/usb/gadget/pxa27x_udc.h
@@ -0,0 +1,487 @@
+/*
+ * linux/drivers/usb/gadget/pxa27x_udc.h
+ * Intel PXA27x on-chip full speed USB device controller
+ *
+ * Inspired by original driver by Frank Becker, David Brownell, and others.
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __LINUX_USB_GADGET_PXA27X_H
+#define __LINUX_USB_GADGET_PXA27X_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+/*
+ * Register definitions
+ */
+/* Offsets */
+#define UDCCR 0x0000 /* UDC Control Register */
+#define UDCICR0 0x0004 /* UDC Interrupt Control Register0 */
+#define UDCICR1 0x0008 /* UDC Interrupt Control Register1 */
+#define UDCISR0 0x000C /* UDC Interrupt Status Register 0 */
+#define UDCISR1 0x0010 /* UDC Interrupt Status Register 1 */
+#define UDCFNR 0x0014 /* UDC Frame Number Register */
+#define UDCOTGICR 0x0018 /* UDC On-The-Go interrupt control */
+#define UP2OCR 0x0020 /* USB Port 2 Output Control register */
+#define UP3OCR 0x0024 /* USB Port 3 Output Control register */
+#define UDCCSRn(x) (0x0100 + ((x)<<2)) /* UDC Control/Status register */
+#define UDCBCRn(x) (0x0200 + ((x)<<2)) /* UDC Byte Count Register */
+#define UDCDRn(x) (0x0300 + ((x)<<2)) /* UDC Data Register */
+#define UDCCRn(x) (0x0400 + ((x)<<2)) /* UDC Control Register */
+
+#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */
+#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation
+ Protocol Port Support */
+#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol
+ Support */
+#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol
+ Enable */
+#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */
+#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */
+#define UDCCR_ACN_S 11
+#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */
+#define UDCCR_AIN_S 8
+#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface
+ Setting Number */
+#define UDCCR_AAISN_S 5
+#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active
+ Configuration */
+#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration
+ Error */
+#define UDCCR_UDR (1 << 2) /* UDC Resume */
+#define UDCCR_UDA (1 << 1) /* UDC Active */
+#define UDCCR_UDE (1 << 0) /* UDC Enable */
+
+#define UDCICR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */
+#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */
+#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */
+#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */
+#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */
+#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */
+#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */
+#define UDCICR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
+
+#define UDCISR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCISR1_IRCC (1 << 31) /* IntReq - Configuration Change */
+#define UDCISR1_IRSOF (1 << 30) /* IntReq - Start of Frame */
+#define UDCISR1_IRRU (1 << 29) /* IntReq - Resume */
+#define UDCISR1_IRSU (1 << 28) /* IntReq - Suspend */
+#define UDCISR1_IRRS (1 << 27) /* IntReq - Reset */
+#define UDCISR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
+
+#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */
+#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt
+ Rising Edge Interrupt Enable */
+#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt
+ Falling Edge Interrupt Enable */
+#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge
+ Interrupt Enable */
+#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge
+ Interrupt Enable */
+#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising
+ Edge Interrupt Enable */
+#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling
+ Edge Interrupt Enable */
+#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge
+ Interrupt Enable */
+
+/* Host Port 2 field bits */
+#define UP2OCR_CPVEN (1 << 0) /* Charge Pump Vbus Enable */
+#define UP2OCR_CPVPE (1 << 1) /* Charge Pump Vbus Pulse Enable */
+ /* Transceiver enablers */
+#define UP2OCR_DPPDE (1 << 2) /* D+ Pull Down Enable */
+#define UP2OCR_DMPDE (1 << 3) /* D- Pull Down Enable */
+#define UP2OCR_DPPUE (1 << 4) /* D+ Pull Up Enable */
+#define UP2OCR_DMPUE (1 << 5) /* D- Pull Up Enable */
+#define UP2OCR_DPPUBE (1 << 6) /* D+ Pull Up Bypass Enable */
+#define UP2OCR_DMPUBE (1 << 7) /* D- Pull Up Bypass Enable */
+#define UP2OCR_EXSP (1 << 8) /* External Transceiver Speed Control */
+#define UP2OCR_EXSUS (1 << 9) /* External Transceiver Speed Enable */
+#define UP2OCR_IDON (1 << 10) /* OTG ID Read Enable */
+#define UP2OCR_HXS (1 << 16) /* Transceiver Output Select */
+#define UP2OCR_HXOE (1 << 17) /* Transceiver Output Enable */
+#define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */
+
+#define UDCCSR0_SA (1 << 7) /* Setup Active */
+#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */
+#define UDCCSR0_FST (1 << 5) /* Force Stall */
+#define UDCCSR0_SST (1 << 4) /* Sent Stall */
+#define UDCCSR0_DME (1 << 3) /* DMA Enable */
+#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */
+#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */
+#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */
+
+#define UDCCSR_DPE (1 << 9) /* Data Packet Error */
+#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */
+#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */
+#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */
+#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */
+#define UDCCSR_FST (1 << 5) /* Force STALL */
+#define UDCCSR_SST (1 << 4) /* Sent STALL */
+#define UDCCSR_DME (1 << 3) /* DMA Enable */
+#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */
+#define UDCCSR_PC (1 << 1) /* Packet Complete */
+#define UDCCSR_FS (1 << 0) /* FIFO needs service */
+
+#define UDCCONR_CN (0x03 << 25) /* Configuration Number */
+#define UDCCONR_CN_S 25
+#define UDCCONR_IN (0x07 << 22) /* Interface Number */
+#define UDCCONR_IN_S 22
+#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */
+#define UDCCONR_AISN_S 19
+#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */
+#define UDCCONR_EN_S 15
+#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */
+#define UDCCONR_ET_S 13
+#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */
+#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */
+#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */
+#define UDCCONR_ET_NU (0x00 << 13) /* Not used */
+#define UDCCONR_ED (1 << 12) /* Endpoint Direction */
+#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */
+#define UDCCONR_MPS_S 2
+#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */
+#define UDCCONR_EE (1 << 0) /* Endpoint Enable */
+
+#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_SMAC | UDCCR_UDR | UDCCR_UDE)
+#define UDCCSR_WR_MASK (UDCCSR_DME | UDCCSR_FST)
+#define UDC_FNR_MASK (0x7ff)
+#define UDC_BCR_MASK (0x3ff)
+
+/*
+ * UDCCR = UDC Endpoint Configuration Registers
+ * UDCCSR = UDC Control/Status Register for this EP
+ * UDCBCR = UDC Byte Count Remaining (contents of OUT fifo)
+ * UDCDR = UDC Endpoint Data Register (the fifo)
+ */
+#define ofs_UDCCR(ep) (UDCCRn(ep->idx))
+#define ofs_UDCCSR(ep) (UDCCSRn(ep->idx))
+#define ofs_UDCBCR(ep) (UDCBCRn(ep->idx))
+#define ofs_UDCDR(ep) (UDCDRn(ep->idx))
+
+/* Register access macros */
+#define udc_ep_readl(ep, reg) \
+ __raw_readl((ep)->dev->regs + ofs_##reg(ep))
+#define udc_ep_writel(ep, reg, value) \
+ __raw_writel((value), ep->dev->regs + ofs_##reg(ep))
+#define udc_ep_readb(ep, reg) \
+ __raw_readb((ep)->dev->regs + ofs_##reg(ep))
+#define udc_ep_writeb(ep, reg, value) \
+ __raw_writeb((value), ep->dev->regs + ofs_##reg(ep))
+#define udc_readl(dev, reg) \
+ __raw_readl((dev)->regs + (reg))
+#define udc_writel(udc, reg, value) \
+ __raw_writel((value), (udc)->regs + (reg))
+
+#define UDCCSR_MASK (UDCCSR_FST | UDCCSR_DME)
+#define UDCCISR0_EP_MASK ~0
+#define UDCCISR1_EP_MASK 0xffff
+#define UDCCSR0_CTRL_REQ_MASK (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)
+
+#define EPIDX(ep) (ep->idx)
+#define EPADDR(ep) (ep->addr)
+#define EPXFERTYPE(ep) (ep->type)
+#define EPNAME(ep) (ep->name)
+#define is_ep0(ep) (!ep->idx)
+#define EPXFERTYPE_is_ISO(ep) (EPXFERTYPE(ep) == USB_ENDPOINT_XFER_ISOC)
+
+/*
+ * Endpoint definitions
+ *
+ * Once enabled, pxa endpoint configuration is freezed, and cannot change
+ * unless a reset happens or the udc is disabled.
+ * Therefore, we must define all pxa potential endpoint definitions needed for
+ * all gadget and set them up before the udc is enabled.
+ *
+ * As the architecture chosen is fully static, meaning the pxa endpoint
+ * configurations are set up once and for all, we must provide a way to match
+ * one usb endpoint (usb_ep) to several pxa endpoints. The reason is that gadget
+ * layer autoconf doesn't choose the usb_ep endpoint on (config, interface, alt)
+ * criteria, while the pxa architecture requires that.
+ *
+ * The solution is to define several pxa endpoints matching one usb_ep. Ex:
+ * - "ep1-in" matches pxa endpoint EPA (which is an IN ep at addr 1, when
+ * the udc talks on (config=3, interface=0, alt=0)
+ * - "ep1-in" matches pxa endpoint EPB (which is an IN ep at addr 1, when
+ * the udc talks on (config=3, interface=0, alt=1)
+ * - "ep1-in" matches pxa endpoint EPC (which is an IN ep at addr 1, when
+ * the udc talks on (config=2, interface=0, alt=0)
+ *
+ * We'll define the pxa endpoint by its index (EPA => idx=1, EPB => idx=2, ...)
+ */
+
+/*
+ * Endpoint definition helpers
+ */
+#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \
+{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \
+ .desc = { .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \
+ .bmAttributes = type, \
+ .wMaxPacketSize = maxpkt, }, \
+ .dev = &memory \
+}
+#define USB_EP_BULK(addr, bname, dir) \
+ USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE)
+#define USB_EP_ISO(addr, bname, dir) \
+ USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE)
+#define USB_EP_INT(addr, bname, dir) \
+ USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE)
+#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1)
+#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0)
+#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1)
+#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0)
+#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1)
+#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, 0, EP0_FIFO_SIZE)
+
+#define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \
+{ \
+ .dev = &memory, \
+ .name = "ep" #_idx, \
+ .idx = _idx, .enabled = 0, \
+ .dir_in = dir, .addr = _addr, \
+ .config = _config, .interface = iface, .alternate = altset, \
+ .type = _type, .fifo_size = maxpkt, \
+}
+#define PXA_EP_BULK(_idx, addr, dir, config, iface, alt) \
+ PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE, \
+ config, iface, alt)
+#define PXA_EP_ISO(_idx, addr, dir, config, iface, alt) \
+ PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE, \
+ config, iface, alt)
+#define PXA_EP_INT(_idx, addr, dir, config, iface, alt) \
+ PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE, \
+ config, iface, alt)
+#define PXA_EP_IN_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 1, c, f, a)
+#define PXA_EP_OUT_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 0, c, f, a)
+#define PXA_EP_IN_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 1, c, f, a)
+#define PXA_EP_OUT_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 0, c, f, a)
+#define PXA_EP_IN_INT(i, adr, c, f, a) PXA_EP_INT(i, adr, 1, c, f, a)
+#define PXA_EP_CTRL PXA_EP_DEF(0, 0, 0, 0, EP0_FIFO_SIZE, 0, 0, 0)
+
+struct pxa27x_udc;
+
+struct stats {
+ unsigned long in_ops;
+ unsigned long out_ops;
+ unsigned long in_bytes;
+ unsigned long out_bytes;
+ unsigned long irqs;
+};
+
+/**
+ * struct udc_usb_ep - container of each usb_ep structure
+ * @usb_ep: usb endpoint
+ * @desc: usb descriptor, especially type and address
+ * @dev: udc managing this endpoint
+ * @pxa_ep: matching pxa_ep (cache of find_pxa_ep() call)
+ */
+struct udc_usb_ep {
+ struct usb_ep usb_ep;
+ struct usb_endpoint_descriptor desc;
+ struct pxa_udc *dev;
+ struct pxa_ep *pxa_ep;
+};
+
+/**
+ * struct pxa_ep - pxa endpoint
+ * @dev: udc device
+ * @queue: requests queue
+ * @lock: lock to pxa_ep data (queues and stats)
+ * @enabled: true when endpoint enabled (not stopped by gadget layer)
+ * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX)
+ * @name: endpoint name (for trace/debug purpose)
+ * @dir_in: 1 if IN endpoint, 0 if OUT endpoint
+ * @addr: usb endpoint number
+ * @config: configuration in which this endpoint is active
+ * @interface: interface in which this endpoint is active
+ * @alternate: altsetting in which this endpoitn is active
+ * @fifo_size: max packet size in the endpoint fifo
+ * @type: endpoint type (bulk, iso, int, ...)
+ * @udccsr_value: save register of UDCCSR0 for suspend/resume
+ * @udccr_value: save register of UDCCR for suspend/resume
+ * @stats: endpoint statistics
+ *
+ * The *PROBLEM* is that pxa's endpoint configuration scheme is both misdesigned
+ * (cares about config/interface/altsetting, thus placing needless limits on
+ * device capability) and full of implementation bugs forcing it to be set up
+ * for use more or less like a pxa255.
+ *
+ * As we define the pxa_ep statically, we must guess all needed pxa_ep for all
+ * gadget which may work with this udc driver.
+ */
+struct pxa_ep {
+ struct pxa_udc *dev;
+
+ struct list_head queue;
+ spinlock_t lock; /* Protects this structure */
+ /* (queues, stats) */
+ unsigned enabled:1;
+
+ unsigned idx:5;
+ char *name;
+
+ /*
+ * Specific pxa endpoint data, needed for hardware initialization
+ */
+ unsigned dir_in:1;
+ unsigned addr:3;
+ unsigned config:2;
+ unsigned interface:3;
+ unsigned alternate:3;
+ unsigned fifo_size;
+ unsigned type;
+
+#ifdef CONFIG_PM
+ u32 udccsr_value;
+ u32 udccr_value;
+#endif
+ struct stats stats;
+};
+
+/**
+ * struct pxa27x_request - container of each usb_request structure
+ * @req: usb request
+ * @udc_usb_ep: usb endpoint the request was submitted on
+ * @in_use: sanity check if request already queued on an pxa_ep
+ * @queue: linked list of requests, linked on pxa_ep->queue
+ */
+struct pxa27x_request {
+ struct usb_request req;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned in_use:1;
+ struct list_head queue;
+};
+
+enum ep0_state {
+ WAIT_FOR_SETUP,
+ SETUP_STAGE,
+ IN_DATA_STAGE,
+ OUT_DATA_STAGE,
+ IN_STATUS_STAGE,
+ OUT_STATUS_STAGE,
+ STALL,
+ WAIT_ACK_SET_CONF_INTERF
+};
+
+static char *ep0_state_name[] = {
+ "WAIT_FOR_SETUP", "SETUP_STAGE", "IN_DATA_STAGE", "OUT_DATA_STAGE",
+ "IN_STATUS_STAGE", "OUT_STATUS_STAGE", "STALL",
+ "WAIT_ACK_SET_CONF_INTERF"
+};
+#define EP0_STNAME(udc) ep0_state_name[(udc)->ep0state]
+
+#define EP0_FIFO_SIZE 16U
+#define BULK_FIFO_SIZE 64U
+#define ISO_FIFO_SIZE 256U
+#define INT_FIFO_SIZE 16U
+
+struct udc_stats {
+ unsigned long irqs_reset;
+ unsigned long irqs_suspend;
+ unsigned long irqs_resume;
+ unsigned long irqs_reconfig;
+};
+
+#define NR_USB_ENDPOINTS (1 + 5) /* ep0 + ep1in-bulk + .. + ep3in-iso */
+#define NR_PXA_ENDPOINTS (1 + 14) /* ep0 + epA + epB + .. + epX */
+
+/**
+ * struct pxa_udc - udc structure
+ * @regs: mapped IO space
+ * @irq: udc irq
+ * @clk: udc clock
+ * @usb_gadget: udc gadget structure
+ * @driver: bound gadget (zero, g_ether, g_file_storage, ...)
+ * @dev: device
+ * @mach: machine info, used to activate specific GPIO
+ * @ep0state: control endpoint state machine state
+ * @stats: statistics on udc usage
+ * @udc_usb_ep: array of usb endpoints offered by the gadget
+ * @pxa_ep: array of pxa available endpoints
+ * @config: UDC active configuration
+ * @last_interface: UDC interface of the last SET_INTERFACE host request
+ * @last_alternate: UDC altsetting of the last SET_INTERFACE host request
+ * @udccsr0: save of udccsr0 in case of suspend
+ * @debugfs_root: root entry of debug filesystem
+ * @debugfs_state: debugfs entry for "udcstate"
+ * @debugfs_queues: debugfs entry for "queues"
+ * @debugfs_eps: debugfs entry for "epstate"
+ */
+struct pxa_udc {
+ void __iomem *regs;
+ int irq;
+ struct clk *clk;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct device *dev;
+ struct pxa2xx_udc_mach_info *mach;
+
+ enum ep0_state ep0state;
+ struct udc_stats stats;
+
+ struct udc_usb_ep udc_usb_ep[NR_USB_ENDPOINTS];
+ struct pxa_ep pxa_ep[NR_PXA_ENDPOINTS];
+
+ unsigned config:2;
+ unsigned last_interface:3;
+ unsigned last_alternate:3;
+
+#ifdef CONFIG_PM
+ unsigned udccsr0;
+#endif
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ struct dentry *debugfs_root;
+ struct dentry *debugfs_state;
+ struct dentry *debugfs_queues;
+ struct dentry *debugfs_eps;
+#endif
+};
+
+static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct pxa_udc, gadget);
+}
+
+/*
+ * Debugging/message support
+ */
+#define ep_dbg(ep, fmt, arg...) \
+ dev_dbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_vdbg(ep, fmt, arg...) \
+ dev_vdbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_err(ep, fmt, arg...) \
+ dev_err(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_info(ep, fmt, arg...) \
+ dev_info(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_warn(ep, fmt, arg...) \
+ dev_warn(ep->dev->dev, "%s:%s:" fmt, EPNAME(ep), __func__, ## arg)
+
+#endif /* __LINUX_USB_GADGET_PXA27X_H */
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 8d158e5640e..54cdd6f9403 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -135,7 +135,10 @@ struct gs_port {
int port_in_use; /* open/close in progress */
wait_queue_head_t port_write_wait;/* waiting to write */
struct gs_buf *port_write_buf;
- struct usb_cdc_line_coding port_line_coding;
+ struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
+ u16 port_handshake_bits;
+#define RS232_RTS (1 << 1)
+#define RS232_DTE (1 << 0)
};
/* the device structure holds info for the USB device */
@@ -199,6 +202,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
static int gs_setup_class(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl);
static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
+static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+ struct usb_request *req);
static void gs_disconnect(struct usb_gadget *gadget);
static int gs_set_config(struct gs_dev *dev, unsigned config);
static void gs_reset_config(struct gs_dev *dev);
@@ -406,7 +411,7 @@ static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
.bLength = sizeof(gs_acm_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ACM_TYPE,
- .bmCapabilities = 0,
+ .bmCapabilities = (1 << 1),
};
static const struct usb_cdc_union_desc gs_union_desc = {
@@ -1502,6 +1507,8 @@ static int gs_setup(struct usb_gadget *gadget,
u16 wValue = le16_to_cpu(ctrl->wValue);
u16 wLength = le16_to_cpu(ctrl->wLength);
+ req->complete = gs_setup_complete;
+
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
ret = gs_setup_standard(gadget,ctrl);
@@ -1679,18 +1686,14 @@ static int gs_setup_class(struct usb_gadget *gadget,
switch (ctrl->bRequest) {
case USB_CDC_REQ_SET_LINE_CODING:
- /* FIXME Submit req to read the data; have its completion
- * handler copy that data to port->port_line_coding (iff
- * it's valid) and maybe pass it on. Until then, fail.
- */
- pr_warning("gs_setup: set_line_coding "
- "unuspported\n");
+ if (wLength != sizeof(struct usb_cdc_line_coding))
+ break;
+ ret = wLength;
+ req->complete = gs_setup_complete_set_line_coding;
break;
case USB_CDC_REQ_GET_LINE_CODING:
- port = dev->dev_port[0]; /* ACM only has one port */
- ret = min(wLength,
- (u16)sizeof(struct usb_cdc_line_coding));
+ ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding));
if (port) {
spin_lock(&port->port_lock);
memcpy(req->buf, &port->port_line_coding, ret);
@@ -1699,15 +1702,27 @@ static int gs_setup_class(struct usb_gadget *gadget,
break;
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- /* FIXME Submit req to read the data; have its completion
- * handler use that to set the state (iff it's valid) and
- * maybe pass it on. Until then, fail.
- */
- pr_warning("gs_setup: set_control_line_state "
- "unuspported\n");
+ if (wLength != 0)
+ break;
+ ret = 0;
+ if (port) {
+ /* REVISIT: we currently just remember this data.
+ * If we change that, update whatever hardware needs
+ * updating.
+ */
+ spin_lock(&port->port_lock);
+ port->port_handshake_bits = wValue;
+ spin_unlock(&port->port_lock);
+ }
break;
default:
+ /* NOTE: strictly speaking, we should accept AT-commands
+ * using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE.
+ * But our call management descriptor says we don't handle
+ * call management, so we should be able to get by without
+ * handling those "required" commands (except by stalling).
+ */
pr_err("gs_setup: unknown class request, "
"type=%02x, request=%02x, value=%04x, "
"index=%04x, length=%d\n",
@@ -1719,6 +1734,42 @@ static int gs_setup_class(struct usb_gadget *gadget,
return ret;
}
+static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct gs_dev *dev = ep->driver_data;
+ struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
+
+ switch (req->status) {
+ case 0:
+ /* normal completion */
+ if (req->actual != sizeof(port->port_line_coding))
+ usb_ep_set_halt(ep);
+ else if (port) {
+ struct usb_cdc_line_coding *value = req->buf;
+
+ /* REVISIT: we currently just remember this data.
+ * If we change that, (a) validate it first, then
+ * (b) update whatever hardware needs updating.
+ */
+ spin_lock(&port->port_lock);
+ port->port_line_coding = *value;
+ spin_unlock(&port->port_lock);
+ }
+ break;
+
+ case -ESHUTDOWN:
+ /* disconnect */
+ gs_free_req(ep, req);
+ break;
+
+ default:
+ /* unexpected */
+ break;
+ }
+ return;
+}
+
/*
* gs_setup_complete
*/
@@ -1906,6 +1957,11 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
}
+ /* REVISIT the ACM mode should be able to actually *issue* some
+ * notifications, for at least serial state change events if
+ * not also for network connection; say so in bmCapabilities.
+ */
+
pr_info("gs_set_config: %s configured, %s speed %s config\n",
GS_LONG_NAME,
gadget->speed == USB_SPEED_HIGH ? "high" : "full",
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index d3d4f4048e6..fce4924dbbe 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -23,9 +23,7 @@
/*
* Gadget Zero only needs two bulk endpoints, and is an example of how you
* can write a hardware-agnostic gadget driver running inside a USB device.
- *
- * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
- * affect most of the driver.
+ * Some hardware details are visible, but don't affect most of the driver.
*
* Use it with the Linux host/master side "usbtest" driver to get a basic
* functional test of your device-side usb stack, or with "usb-skeleton".
@@ -37,6 +35,7 @@
* buflen=N default N=4096, buffer size used
* qlen=N default N=32, how many buffers in the loopback queue
* loopdefault default false, list loopback config first
+ * autoresume=N default N=0, seconds before triggering remote wakeup
*
* Many drivers will only have one configuration, letting them be much
* simpler if they also don't support high speed operation (like this
@@ -62,13 +61,13 @@
/*-------------------------------------------------------------------------*/
-#define DRIVER_VERSION "Lughnasadh, 2007"
+#define DRIVER_VERSION "Earth Day 2008"
-static const char shortname [] = "zero";
-static const char longname [] = "Gadget Zero";
+static const char shortname[] = "zero";
+static const char longname[] = "Gadget Zero";
-static const char source_sink [] = "source and sink data";
-static const char loopback [] = "loop input to output";
+static const char source_sink[] = "source and sink data";
+static const char loopback[] = "loop input to output";
/*-------------------------------------------------------------------------*/
@@ -120,16 +119,16 @@ static unsigned buflen = 4096;
static unsigned qlen = 32;
static unsigned pattern = 0;
-module_param (buflen, uint, S_IRUGO);
-module_param (qlen, uint, S_IRUGO);
-module_param (pattern, uint, S_IRUGO|S_IWUSR);
+module_param(buflen, uint, S_IRUGO);
+module_param(qlen, uint, S_IRUGO);
+module_param(pattern, uint, S_IRUGO|S_IWUSR);
/*
* if it's nonzero, autoresume says how many seconds to wait
* before trying to wake up the host after suspend.
*/
static unsigned autoresume = 0;
-module_param (autoresume, uint, 0);
+module_param(autoresume, uint, 0);
/*
* Normally the "loopback" configuration is second (index 1) so
@@ -138,8 +137,7 @@ module_param (autoresume, uint, 0);
* Or controllers (like superh) that only support one config.
*/
static int loopdefault = 0;
-
-module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
+module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
/*-------------------------------------------------------------------------*/
@@ -176,24 +174,22 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
#define CONFIG_SOURCE_SINK 3
#define CONFIG_LOOPBACK 2
-static struct usb_device_descriptor
-device_desc = {
+static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = __constant_cpu_to_le16 (0x0200),
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
- .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
- .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
+ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+ .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
.iManufacturer = STRING_MANUFACTURER,
.iProduct = STRING_PRODUCT,
.iSerialNumber = STRING_SERIAL,
.bNumConfigurations = 2,
};
-static struct usb_config_descriptor
-source_sink_config = {
+static struct usb_config_descriptor source_sink_config = {
.bLength = sizeof source_sink_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -205,8 +201,7 @@ source_sink_config = {
.bMaxPower = 1, /* self-powered */
};
-static struct usb_config_descriptor
-loopback_config = {
+static struct usb_config_descriptor loopback_config = {
.bLength = sizeof loopback_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -218,8 +213,7 @@ loopback_config = {
.bMaxPower = 1, /* self-powered */
};
-static struct usb_otg_descriptor
-otg_descriptor = {
+static struct usb_otg_descriptor otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
@@ -228,8 +222,7 @@ otg_descriptor = {
/* one interface in each configuration */
-static const struct usb_interface_descriptor
-source_sink_intf = {
+static const struct usb_interface_descriptor source_sink_intf = {
.bLength = sizeof source_sink_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -238,8 +231,7 @@ source_sink_intf = {
.iInterface = STRING_SOURCE_SINK,
};
-static const struct usb_interface_descriptor
-loopback_intf = {
+static const struct usb_interface_descriptor loopback_intf = {
.bLength = sizeof loopback_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -250,8 +242,7 @@ loopback_intf = {
/* two full speed bulk endpoints; their use is config-dependent */
-static struct usb_endpoint_descriptor
-fs_source_desc = {
+static struct usb_endpoint_descriptor fs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -259,8 +250,7 @@ fs_source_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor
-fs_sink_desc = {
+static struct usb_endpoint_descriptor fs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -268,7 +258,7 @@ fs_sink_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static const struct usb_descriptor_header *fs_source_sink_function [] = {
+static const struct usb_descriptor_header *fs_source_sink_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &fs_sink_desc,
@@ -276,7 +266,7 @@ static const struct usb_descriptor_header *fs_source_sink_function [] = {
NULL,
};
-static const struct usb_descriptor_header *fs_loopback_function [] = {
+static const struct usb_descriptor_header *fs_loopback_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &fs_sink_desc,
@@ -293,36 +283,33 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
* for the config descriptor.
*/
-static struct usb_endpoint_descriptor
-hs_source_desc = {
+static struct usb_endpoint_descriptor hs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = __constant_cpu_to_le16 (512),
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor
-hs_sink_desc = {
+static struct usb_endpoint_descriptor hs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = __constant_cpu_to_le16 (512),
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
};
-static struct usb_qualifier_descriptor
-dev_qualifier = {
+static struct usb_qualifier_descriptor dev_qualifier = {
.bLength = sizeof dev_qualifier,
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
- .bcdUSB = __constant_cpu_to_le16 (0x0200),
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
.bNumConfigurations = 2,
};
-static const struct usb_descriptor_header *hs_source_sink_function [] = {
+static const struct usb_descriptor_header *hs_source_sink_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &hs_source_desc,
@@ -330,7 +317,7 @@ static const struct usb_descriptor_header *hs_source_sink_function [] = {
NULL,
};
-static const struct usb_descriptor_header *hs_loopback_function [] = {
+static const struct usb_descriptor_header *hs_loopback_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &hs_source_desc,
@@ -355,7 +342,7 @@ static char serial[] = "0123456789.0123456789.0123456789";
/* static strings, in UTF-8 */
-static struct usb_string strings [] = {
+static struct usb_string strings[] = {
{ STRING_MANUFACTURER, manufacturer, },
{ STRING_PRODUCT, longname, },
{ STRING_SERIAL, serial, },
@@ -364,7 +351,7 @@ static struct usb_string strings [] = {
{ } /* end of list */
};
-static struct usb_gadget_strings stringtab = {
+static struct usb_gadget_strings stringtab = {
.language = 0x0409, /* en-us */
.strings = strings,
};
@@ -387,8 +374,7 @@ static struct usb_gadget_strings stringtab = {
* high bandwidth modes at high speed. (Maybe work like Intel's test
* device?)
*/
-static int
-config_buf (struct usb_gadget *gadget,
+static int config_buf(struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
int is_source_sink;
@@ -419,7 +405,7 @@ config_buf (struct usb_gadget *gadget,
if (!gadget_is_otg(gadget))
function++;
- len = usb_gadget_config_buf (is_source_sink
+ len = usb_gadget_config_buf(is_source_sink
? &source_sink_config
: &loopback_config,
buf, USB_BUFSIZ, function);
@@ -431,27 +417,26 @@ config_buf (struct usb_gadget *gadget,
/*-------------------------------------------------------------------------*/
-static struct usb_request *
-alloc_ep_req (struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
{
struct usb_request *req;
- req = usb_ep_alloc_request (ep, GFP_ATOMIC);
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (req) {
req->length = length;
req->buf = kmalloc(length, GFP_ATOMIC);
if (!req->buf) {
- usb_ep_free_request (ep, req);
+ usb_ep_free_request(ep, req);
req = NULL;
}
}
return req;
}
-static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
+static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
kfree(req->buf);
- usb_ep_free_request (ep, req);
+ usb_ep_free_request(ep, req);
}
/*-------------------------------------------------------------------------*/
@@ -472,7 +457,7 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
/* optionally require specific source/sink data patterns */
static int
-check_read_data (
+check_read_data(
struct zero_dev *dev,
struct usb_ep *ep,
struct usb_request *req
@@ -498,8 +483,8 @@ check_read_data (
continue;
break;
}
- ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
- usb_ep_set_halt (ep);
+ ERROR(dev, "bad OUT byte, buf[%d] = %d\n", i, *buf);
+ usb_ep_set_halt(ep);
return -EINVAL;
}
return 0;
@@ -512,7 +497,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
switch (pattern) {
case 0:
- memset (req->buf, 0, req->length);
+ memset(req->buf, 0, req->length);
break;
case 1:
for (i = 0; i < req->length; i++)
@@ -525,7 +510,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
* irq delay between end of one request and start of the next.
* that prevents using hardware dma queues.
*/
-static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
+static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
{
struct zero_dev *dev = ep->driver_data;
int status = req->status;
@@ -534,8 +519,8 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
case 0: /* normal completion? */
if (ep == dev->out_ep) {
- check_read_data (dev, ep, req);
- memset (req->buf, 0x55, req->length);
+ check_read_data(dev, ep, req);
+ memset(req->buf, 0x55, req->length);
} else
reinit_write_data(ep, req);
break;
@@ -544,11 +529,11 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
- VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
+ VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
req->actual, req->length);
if (ep == dev->out_ep)
- check_read_data (dev, ep, req);
- free_ep_req (ep, req);
+ check_read_data(dev, ep, req);
+ free_ep_req(ep, req);
return;
case -EOVERFLOW: /* buffer overrun on read means that
@@ -557,18 +542,18 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
*/
default:
#if 1
- DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
+ DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
#endif
case -EREMOTEIO: /* short read */
break;
}
- status = usb_ep_queue (ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
- ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
+ ERROR(dev, "kill %s: resubmit %d bytes --> %d\n",
ep->name, req->length, status);
- usb_ep_set_halt (ep);
+ usb_ep_set_halt(ep);
/* FIXME recover later ... somehow */
}
}
@@ -578,24 +563,24 @@ static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
struct usb_request *req;
int status;
- req = alloc_ep_req (ep, buflen);
+ req = alloc_ep_req(ep, buflen);
if (!req)
return NULL;
- memset (req->buf, 0, req->length);
+ memset(req->buf, 0, req->length);
req->complete = source_sink_complete;
- if (strcmp (ep->name, EP_IN_NAME) == 0)
+ if (strcmp(ep->name, EP_IN_NAME) == 0)
reinit_write_data(ep, req);
else
- memset (req->buf, 0x55, req->length);
+ memset(req->buf, 0x55, req->length);
status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
struct zero_dev *dev = ep->driver_data;
- ERROR (dev, "start %s --> %d\n", ep->name, status);
- free_ep_req (ep, req);
+ ERROR(dev, "start %s --> %d\n", ep->name, status);
+ free_ep_req(ep, req);
req = NULL;
}
@@ -608,34 +593,34 @@ static int set_source_sink_config(struct zero_dev *dev)
struct usb_ep *ep;
struct usb_gadget *gadget = dev->gadget;
- gadget_for_each_ep (ep, gadget) {
+ gadget_for_each_ep(ep, gadget) {
const struct usb_endpoint_descriptor *d;
/* one endpoint writes (sources) zeroes in (to the host) */
- if (strcmp (ep->name, EP_IN_NAME) == 0) {
- d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
- result = usb_ep_enable (ep, d);
+ if (strcmp(ep->name, EP_IN_NAME) == 0) {
+ d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
if (source_sink_start_ep(ep) != NULL) {
dev->in_ep = ep;
continue;
}
- usb_ep_disable (ep);
+ usb_ep_disable(ep);
result = -EIO;
}
/* one endpoint reads (sinks) anything out (from the host) */
- } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
- d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
- result = usb_ep_enable (ep, d);
+ } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+ d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
if (source_sink_start_ep(ep) != NULL) {
dev->out_ep = ep;
continue;
}
- usb_ep_disable (ep);
+ usb_ep_disable(ep);
result = -EIO;
}
@@ -644,11 +629,11 @@ static int set_source_sink_config(struct zero_dev *dev)
continue;
/* stop on error */
- ERROR (dev, "can't start %s, result %d\n", ep->name, result);
+ ERROR(dev, "can't start %s, result %d\n", ep->name, result);
break;
}
if (result == 0)
- DBG (dev, "buflen %d\n", buflen);
+ DBG(dev, "buflen %d\n", buflen);
/* caller is responsible for cleanup on error */
return result;
@@ -656,7 +641,7 @@ static int set_source_sink_config(struct zero_dev *dev)
/*-------------------------------------------------------------------------*/
-static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
+static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
{
struct zero_dev *dev = ep->driver_data;
int status = req->status;
@@ -668,19 +653,19 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
/* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
req->length = req->actual;
- status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
if (status == 0)
return;
/* "should never get here" */
- ERROR (dev, "can't loop %s to %s: %d\n",
+ ERROR(dev, "can't loop %s to %s: %d\n",
ep->name, dev->in_ep->name,
status);
}
/* queue the buffer for some later OUT packet */
req->length = buflen;
- status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
if (status == 0)
return;
@@ -688,7 +673,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
/* FALLTHROUGH */
default:
- ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name,
+ ERROR(dev, "%s loop complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
/* FALLTHROUGH */
@@ -700,7 +685,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
- free_ep_req (ep, req);
+ free_ep_req(ep, req);
return;
}
}
@@ -711,13 +696,13 @@ static int set_loopback_config(struct zero_dev *dev)
struct usb_ep *ep;
struct usb_gadget *gadget = dev->gadget;
- gadget_for_each_ep (ep, gadget) {
+ gadget_for_each_ep(ep, gadget) {
const struct usb_endpoint_descriptor *d;
/* one endpoint writes data back IN to the host */
- if (strcmp (ep->name, EP_IN_NAME) == 0) {
- d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
- result = usb_ep_enable (ep, d);
+ if (strcmp(ep->name, EP_IN_NAME) == 0) {
+ d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
dev->in_ep = ep;
@@ -725,9 +710,9 @@ static int set_loopback_config(struct zero_dev *dev)
}
/* one endpoint just reads OUT packets */
- } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
- d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
- result = usb_ep_enable (ep, d);
+ } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+ d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
dev->out_ep = ep;
@@ -739,7 +724,7 @@ static int set_loopback_config(struct zero_dev *dev)
continue;
/* stop on error */
- ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
+ ERROR(dev, "can't enable %s, result %d\n", ep->name, result);
break;
}
@@ -753,19 +738,19 @@ static int set_loopback_config(struct zero_dev *dev)
ep = dev->out_ep;
for (i = 0; i < qlen && result == 0; i++) {
- req = alloc_ep_req (ep, buflen);
+ req = alloc_ep_req(ep, buflen);
if (req) {
req->complete = loopback_complete;
- result = usb_ep_queue (ep, req, GFP_ATOMIC);
+ result = usb_ep_queue(ep, req, GFP_ATOMIC);
if (result)
- DBG (dev, "%s queue req --> %d\n",
+ DBG(dev, "%s queue req --> %d\n",
ep->name, result);
} else
result = -ENOMEM;
}
}
if (result == 0)
- DBG (dev, "qlen %d, buflen %d\n", qlen, buflen);
+ DBG(dev, "qlen %d, buflen %d\n", qlen, buflen);
/* caller is responsible for cleanup on error */
return result;
@@ -773,26 +758,26 @@ static int set_loopback_config(struct zero_dev *dev)
/*-------------------------------------------------------------------------*/
-static void zero_reset_config (struct zero_dev *dev)
+static void zero_reset_config(struct zero_dev *dev)
{
if (dev->config == 0)
return;
- DBG (dev, "reset config\n");
+ DBG(dev, "reset config\n");
/* just disable endpoints, forcing completion of pending i/o.
* all our completion handlers free their requests in this case.
*/
if (dev->in_ep) {
- usb_ep_disable (dev->in_ep);
+ usb_ep_disable(dev->in_ep);
dev->in_ep = NULL;
}
if (dev->out_ep) {
- usb_ep_disable (dev->out_ep);
+ usb_ep_disable(dev->out_ep);
dev->out_ep = NULL;
}
dev->config = 0;
- del_timer (&dev->resume);
+ del_timer(&dev->resume);
}
/* change our operational config. this code must agree with the code
@@ -813,12 +798,12 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
if (number == dev->config)
return 0;
- if (gadget_is_sa1100 (gadget) && dev->config) {
+ if (gadget_is_sa1100(gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
- zero_reset_config (dev);
+ zero_reset_config(dev);
switch (number) {
case CONFIG_SOURCE_SINK:
@@ -837,7 +822,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
if (!result && (!dev->in_ep || !dev->out_ep))
result = -ENODEV;
if (result)
- zero_reset_config (dev);
+ zero_reset_config(dev);
else {
char *speed;
@@ -849,7 +834,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
}
dev->config = number;
- INFO (dev, "%s speed config #%d: %s\n", speed, number,
+ INFO(dev, "%s speed config #%d: %s\n", speed, number,
(number == CONFIG_SOURCE_SINK)
? source_sink : loopback);
}
@@ -858,10 +843,10 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
/*-------------------------------------------------------------------------*/
-static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
+static void zero_setup_complete(struct usb_ep *ep, struct usb_request *req)
{
if (req->status || req->actual != req->length)
- DBG ((struct zero_dev *) ep->driver_data,
+ DBG((struct zero_dev *) ep->driver_data,
"setup complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
}
@@ -874,9 +859,9 @@ static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
* the work is in config-specific setup.
*/
static int
-zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
@@ -895,14 +880,14 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
switch (w_value >> 8) {
case USB_DT_DEVICE:
- value = min (w_length, (u16) sizeof device_desc);
- memcpy (req->buf, &device_desc, value);
+ value = min(w_length, (u16) sizeof device_desc);
+ memcpy(req->buf, &device_desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
if (!gadget_is_dualspeed(gadget))
break;
- value = min (w_length, (u16) sizeof dev_qualifier);
- memcpy (req->buf, &dev_qualifier, value);
+ value = min(w_length, (u16) sizeof dev_qualifier);
+ memcpy(req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
@@ -910,11 +895,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
// FALLTHROUGH
case USB_DT_CONFIG:
- value = config_buf (gadget, req->buf,
+ value = config_buf(gadget, req->buf,
w_value >> 8,
w_value & 0xff);
if (value >= 0)
- value = min (w_length, (u16) value);
+ value = min(w_length, (u16) value);
break;
case USB_DT_STRING:
@@ -923,10 +908,10 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* add string tables for other languages, using
* any UTF-8 characters
*/
- value = usb_gadget_get_string (&stringtab,
+ value = usb_gadget_get_string(&stringtab,
w_value & 0xff, req->buf);
if (value >= 0)
- value = min (w_length, (u16) value);
+ value = min(w_length, (u16) value);
break;
}
break;
@@ -936,20 +921,20 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (ctrl->bRequestType != 0)
goto unknown;
if (gadget->a_hnp_support)
- DBG (dev, "HNP available\n");
+ DBG(dev, "HNP available\n");
else if (gadget->a_alt_hnp_support)
- DBG (dev, "HNP needs a different root port\n");
+ DBG(dev, "HNP needs a different root port\n");
else
- VDBG (dev, "HNP inactive\n");
- spin_lock (&dev->lock);
+ VDBG(dev, "HNP inactive\n");
+ spin_lock(&dev->lock);
value = zero_set_config(dev, w_value);
- spin_unlock (&dev->lock);
+ spin_unlock(&dev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
*(u8 *)req->buf = dev->config;
- value = min (w_length, (u16) 1);
+ value = min(w_length, (u16) 1);
break;
/* until we add altsetting support, or other interfaces,
@@ -959,7 +944,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
goto unknown;
- spin_lock (&dev->lock);
+ spin_lock(&dev->lock);
if (dev->config && w_index == 0 && w_value == 0) {
u8 config = dev->config;
@@ -970,11 +955,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* if we had more than one interface we couldn't
* use this "reset the config" shortcut.
*/
- zero_reset_config (dev);
+ zero_reset_config(dev);
zero_set_config(dev, config);
value = 0;
}
- spin_unlock (&dev->lock);
+ spin_unlock(&dev->lock);
break;
case USB_REQ_GET_INTERFACE:
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
@@ -986,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
}
*(u8 *)req->buf = 0;
- value = min (w_length, (u16) 1);
+ value = min(w_length, (u16) 1);
break;
/*
@@ -1018,7 +1003,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
default:
unknown:
- VDBG (dev,
+ VDBG(dev,
"unknown control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
@@ -1028,11 +1013,11 @@ unknown:
if (value >= 0) {
req->length = value;
req->zero = value < w_length;
- value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+ value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
- DBG (dev, "ep_queue --> %d\n", value);
+ DBG(dev, "ep_queue --> %d\n", value);
req->status = 0;
- zero_setup_complete (gadget->ep0, req);
+ zero_setup_complete(gadget->ep0, req);
}
}
@@ -1040,28 +1025,26 @@ unknown:
return value;
}
-static void
-zero_disconnect (struct usb_gadget *gadget)
+static void zero_disconnect(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
unsigned long flags;
- spin_lock_irqsave (&dev->lock, flags);
- zero_reset_config (dev);
+ spin_lock_irqsave(&dev->lock, flags);
+ zero_reset_config(dev);
/* a more significant application might have some non-usb
* activities to quiesce here, saving resources like power
* or pushing the notification up a network stack.
*/
- spin_unlock_irqrestore (&dev->lock, flags);
+ spin_unlock_irqrestore(&dev->lock, flags);
/* next we may get setup() calls to enumerate new connections;
* or an unbind() during shutdown (including removing module).
*/
}
-static void
-zero_autoresume (unsigned long _dev)
+static void zero_autoresume(unsigned long _dev)
{
struct zero_dev *dev = (struct zero_dev *) _dev;
int status;
@@ -1070,32 +1053,30 @@ zero_autoresume (unsigned long _dev)
* more significant than just a timer firing...
*/
if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
- status = usb_gadget_wakeup (dev->gadget);
- DBG (dev, "wakeup --> %d\n", status);
+ status = usb_gadget_wakeup(dev->gadget);
+ DBG(dev, "wakeup --> %d\n", status);
}
}
/*-------------------------------------------------------------------------*/
-static void /* __init_or_exit */
-zero_unbind (struct usb_gadget *gadget)
+static void zero_unbind(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
- DBG (dev, "unbind\n");
+ DBG(dev, "unbind\n");
/* we've already been disconnected ... no i/o is active */
if (dev->req) {
dev->req->length = USB_BUFSIZ;
- free_ep_req (gadget->ep0, dev->req);
+ free_ep_req(gadget->ep0, dev->req);
}
- del_timer_sync (&dev->resume);
- kfree (dev);
- set_gadget_data (gadget, NULL);
+ del_timer_sync(&dev->resume);
+ kfree(dev);
+ set_gadget_data(gadget, NULL);
}
-static int __init
-zero_bind (struct usb_gadget *gadget)
+static int __init zero_bind(struct usb_gadget *gadget)
{
struct zero_dev *dev;
struct usb_ep *ep;
@@ -1111,8 +1092,8 @@ zero_bind (struct usb_gadget *gadget)
* autoconfigure on any sane usb controller driver,
* but there may also be important quirks to address.
*/
- usb_ep_autoconfig_reset (gadget);
- ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+ usb_ep_autoconfig_reset(gadget);
+ ep = usb_ep_autoconfig(gadget, &fs_source_desc);
if (!ep) {
autoconf_fail:
pr_err("%s: can't autoconfigure on %s\n",
@@ -1122,15 +1103,15 @@ autoconf_fail:
EP_IN_NAME = ep->name;
ep->driver_data = ep; /* claim */
- ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+ ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
if (!ep)
goto autoconf_fail;
EP_OUT_NAME = ep->name;
ep->driver_data = ep; /* claim */
- gcnum = usb_gadget_controller_number (gadget);
+ gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
- device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
else {
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
@@ -1141,7 +1122,7 @@ autoconf_fail:
*/
pr_warning("%s: controller '%s' not recognized\n",
shortname, gadget->name);
- device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
+ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
}
@@ -1149,12 +1130,16 @@ autoconf_fail:
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- spin_lock_init (&dev->lock);
+ spin_lock_init(&dev->lock);
dev->gadget = gadget;
- set_gadget_data (gadget, dev);
+ set_gadget_data(gadget, dev);
+
+ init_timer(&dev->resume);
+ dev->resume.function = zero_autoresume;
+ dev->resume.data = (unsigned long) dev;
/* preallocate control response and buffer */
- dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+ dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
if (!dev->req)
goto enomem;
dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
@@ -1182,11 +1167,8 @@ autoconf_fail:
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- usb_gadget_set_selfpowered (gadget);
+ usb_gadget_set_selfpowered(gadget);
- init_timer (&dev->resume);
- dev->resume.function = zero_autoresume;
- dev->resume.data = (unsigned long) dev;
if (autoresume) {
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1194,45 +1176,43 @@ autoconf_fail:
gadget->ep0->driver_data = dev;
- INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
- INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
+ INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
+ INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
EP_OUT_NAME, EP_IN_NAME);
- snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
gadget->name);
return 0;
enomem:
- zero_unbind (gadget);
+ zero_unbind(gadget);
return -ENOMEM;
}
/*-------------------------------------------------------------------------*/
-static void
-zero_suspend (struct usb_gadget *gadget)
+static void zero_suspend(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
if (gadget->speed == USB_SPEED_UNKNOWN)
return;
if (autoresume) {
- mod_timer (&dev->resume, jiffies + (HZ * autoresume));
- DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
+ mod_timer(&dev->resume, jiffies + (HZ * autoresume));
+ DBG(dev, "suspend, wakeup in %d seconds\n", autoresume);
} else
- DBG (dev, "suspend\n");
+ DBG(dev, "suspend\n");
}
-static void
-zero_resume (struct usb_gadget *gadget)
+static void zero_resume(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
- DBG (dev, "resume\n");
- del_timer (&dev->resume);
+ DBG(dev, "resume\n");
+ del_timer(&dev->resume);
}
@@ -1264,15 +1244,15 @@ MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");
-static int __init init (void)
+static int __init init(void)
{
- return usb_gadget_register_driver (&zero_driver);
+ return usb_gadget_register_driver(&zero_driver);
}
-module_init (init);
+module_init(init);
-static void __exit cleanup (void)
+static void __exit cleanup(void)
{
- usb_gadget_unregister_driver (&zero_driver);
+ usb_gadget_unregister_driver(&zero_driver);
}
-module_exit (cleanup);
+module_exit(cleanup);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 0b87480dd71..33b467a8352 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -4,6 +4,19 @@
comment "USB Host Controller Drivers"
depends on USB
+config USB_C67X00_HCD
+ tristate "Cypress C67x00 HCD support"
+ depends on USB
+ help
+ The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
+ host/peripheral/OTG USB controllers.
+
+ Enable this option to support this chip in host controller mode.
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called c67x00.
+
config USB_EHCI_HCD
tristate "EHCI HCD (USB 2.0) support"
depends on USB && USB_ARCH_HAS_EHCI
@@ -95,6 +108,32 @@ config USB_ISP116X_HCD
To compile this driver as a module, choose M here: the
module will be called isp116x-hcd.
+config USB_ISP1760_HCD
+ tristate "ISP 1760 HCD support"
+ depends on USB && EXPERIMENTAL
+ ---help---
+ The ISP1760 chip is a USB 2.0 host controller.
+
+ This driver does not support isochronous transfers or OTG.
+
+ To compile this driver as a module, choose M here: the
+ module will be called isp1760-hcd.
+
+config USB_ISP1760_PCI
+ bool "Support for the PCI bus"
+ depends on USB_ISP1760_HCD && PCI
+ ---help---
+ Enables support for the device present on the PCI bus.
+ This should only be required if you happen to have the eval kit from
+ NXP and you are going to test it.
+
+config USB_ISP1760_OF
+ bool "Support for the OF platform bus"
+ depends on USB_ISP1760_HCD && OF
+ ---help---
+ Enables support for the device present on the PowerPC
+ OpenFirmware platform bus.
+
config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index bb8e9d44f37..f1edda2dcfd 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -6,6 +6,8 @@ ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
+isp1760-objs := isp1760-hcd.o isp1760-if.o
+
obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
@@ -16,4 +18,4 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-
+obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
new file mode 100644
index 00000000000..4ba96c1e060
--- /dev/null
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -0,0 +1,2231 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * However, the code might contain some bugs. What doesn't work for sure is:
+ * - ISO
+ * - OTG
+ e The interrupt line is configured as active low, level.
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/unaligned.h>
+
+#include "../core/hcd.h"
+#include "isp1760-hcd.h"
+
+static struct kmem_cache *qtd_cachep;
+static struct kmem_cache *qh_cachep;
+
+struct isp1760_hcd {
+ u32 hcs_params;
+ spinlock_t lock;
+ struct inter_packet_info atl_ints[32];
+ struct inter_packet_info int_ints[32];
+ struct memory_chunk memory_pool[BLOCKS];
+
+ /* periodic schedule support */
+#define DEFAULT_I_TDPS 1024
+ unsigned periodic_size;
+ unsigned i_thresh;
+ unsigned long reset_done;
+ unsigned long next_statechange;
+};
+
+static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
+{
+ return (struct isp1760_hcd *) (hcd->hcd_priv);
+}
+static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv)
+{
+ return container_of((void *) priv, struct usb_hcd, hcd_priv);
+}
+
+/* Section 2.2 Host Controller Capability Registers */
+#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
+#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
+#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
+
+/* Section 2.3 Host Controller Operational Registers */
+#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
+#define CMD_RESET (1<<1) /* reset HC not bus */
+#define CMD_RUN (1<<0) /* start/stop HC */
+#define STS_PCD (1<<2) /* port change detect */
+#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
+
+#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
+#define PORT_POWER (1<<12) /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
+#define PORT_RESET (1<<8) /* reset port */
+#define PORT_SUSPEND (1<<7) /* suspend port */
+#define PORT_RESUME (1<<6) /* resume it */
+#define PORT_PE (1<<2) /* port enable */
+#define PORT_CSC (1<<1) /* connect status change */
+#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC)
+
+struct isp1760_qtd {
+ struct isp1760_qtd *hw_next;
+ u8 packet_type;
+ u8 toggle;
+
+ void *data_buffer;
+ /* the rest is HCD-private */
+ struct list_head qtd_list;
+ struct urb *urb;
+ size_t length;
+
+ /* isp special*/
+ u32 status;
+#define URB_COMPLETE_NOTIFY (1 << 0)
+#define URB_ENQUEUED (1 << 1)
+#define URB_TYPE_ATL (1 << 2)
+#define URB_TYPE_INT (1 << 3)
+};
+
+struct isp1760_qh {
+ /* first part defined by EHCI spec */
+ struct list_head qtd_list;
+ struct isp1760_hcd *priv;
+
+ /* periodic schedule info */
+ unsigned short period; /* polling interval */
+ struct usb_device *dev;
+
+ u32 toggle;
+ u32 ping;
+};
+
+#define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED)
+
+static unsigned int isp1760_readl(__u32 __iomem *regs)
+{
+ return readl(regs);
+}
+
+static void isp1760_writel(const unsigned int val, __u32 __iomem *regs)
+{
+ writel(val, regs);
+}
+
+/*
+ * The next two copy via MMIO data to/from the device. memcpy_{to|from}io()
+ * doesn't quite work because some people have to enforce 32-bit access
+ */
+static void priv_read_copy(struct isp1760_hcd *priv, u32 *src,
+ __u32 __iomem *dst, u32 offset, u32 len)
+{
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+ u32 val;
+ u8 *buff8;
+
+ if (!src) {
+ printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len);
+ return;
+ }
+ isp1760_writel(offset, hcd->regs + HC_MEMORY_REG);
+ /* XXX
+ * 90nsec delay, the spec says something how this could be avoided.
+ */
+ mdelay(1);
+
+ while (len >= 4) {
+ *src = __raw_readl(dst);
+ len -= 4;
+ src++;
+ dst++;
+ }
+
+ if (!len)
+ return;
+
+ /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully
+ * allocated.
+ */
+ val = isp1760_readl(dst);
+
+ buff8 = (u8 *)src;
+ while (len) {
+
+ *buff8 = val;
+ val >>= 8;
+ len--;
+ buff8++;
+ }
+}
+
+static void priv_write_copy(const struct isp1760_hcd *priv, const u32 *src,
+ __u32 __iomem *dst, u32 len)
+{
+ while (len >= 4) {
+ __raw_writel(*src, dst);
+ len -= 4;
+ src++;
+ dst++;
+ }
+
+ if (!len)
+ return;
+ /* in case we have 3, 2 or 1 by left. The buffer is allocated and the
+ * extra bytes should not be read by the HW
+ */
+
+ __raw_writel(*src, dst);
+}
+
+/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
+static void init_memory(struct isp1760_hcd *priv)
+{
+ int i;
+ u32 payload;
+
+ payload = 0x1000;
+ for (i = 0; i < BLOCK_1_NUM; i++) {
+ priv->memory_pool[i].start = payload;
+ priv->memory_pool[i].size = BLOCK_1_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload += priv->memory_pool[i].size;
+ }
+
+
+ for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) {
+ priv->memory_pool[i].start = payload;
+ priv->memory_pool[i].size = BLOCK_2_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload += priv->memory_pool[i].size;
+ }
+
+
+ for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) {
+ priv->memory_pool[i].start = payload;
+ priv->memory_pool[i].size = BLOCK_3_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload += priv->memory_pool[i].size;
+ }
+
+ BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE);
+}
+
+static u32 alloc_mem(struct isp1760_hcd *priv, u32 size)
+{
+ int i;
+
+ if (!size)
+ return ISP1760_NULL_POINTER;
+
+ for (i = 0; i < BLOCKS; i++) {
+ if (priv->memory_pool[i].size >= size &&
+ priv->memory_pool[i].free) {
+
+ priv->memory_pool[i].free = 0;
+ return priv->memory_pool[i].start;
+ }
+ }
+
+ printk(KERN_ERR "ISP1760 MEM: can not allocate %d bytes of memory\n",
+ size);
+ printk(KERN_ERR "Current memory map:\n");
+ for (i = 0; i < BLOCKS; i++) {
+ printk(KERN_ERR "Pool %2d size %4d status: %d\n",
+ i, priv->memory_pool[i].size,
+ priv->memory_pool[i].free);
+ }
+ /* XXX maybe -ENOMEM could be possible */
+ BUG();
+ return 0;
+}
+
+static void free_mem(struct isp1760_hcd *priv, u32 mem)
+{
+ int i;
+
+ if (mem == ISP1760_NULL_POINTER)
+ return;
+
+ for (i = 0; i < BLOCKS; i++) {
+ if (priv->memory_pool[i].start == mem) {
+
+ BUG_ON(priv->memory_pool[i].free);
+
+ priv->memory_pool[i].free = 1;
+ return ;
+ }
+ }
+
+ printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n",
+ mem);
+ BUG();
+}
+
+static void isp1760_init_regs(struct usb_hcd *hcd)
+{
+ isp1760_writel(0, hcd->regs + HC_BUFFER_STATUS_REG);
+ isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+ isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+ isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ISO_PTD_SKIPMAP_REG);
+
+ isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ATL_PTD_DONEMAP_REG);
+ isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_INT_PTD_DONEMAP_REG);
+ isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ISO_PTD_DONEMAP_REG);
+}
+
+static int handshake(struct isp1760_hcd *priv, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
+{
+ u32 result;
+
+ do {
+ result = isp1760_readl(ptr);
+ if (result == ~0)
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+ return -ETIMEDOUT;
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset(struct isp1760_hcd *priv)
+{
+ int retval;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+ u32 command = isp1760_readl(hcd->regs + HC_USBCMD);
+
+ command |= CMD_RESET;
+ isp1760_writel(command, hcd->regs + HC_USBCMD);
+ hcd->state = HC_STATE_HALT;
+ priv->next_statechange = jiffies;
+ retval = handshake(priv, hcd->regs + HC_USBCMD,
+ CMD_RESET, 0, 250 * 1000);
+ return retval;
+}
+
+static void qh_destroy(struct isp1760_qh *qh)
+{
+ BUG_ON(!list_empty(&qh->qtd_list));
+ kmem_cache_free(qh_cachep, qh);
+}
+
+static struct isp1760_qh *isp1760_qh_alloc(struct isp1760_hcd *priv,
+ gfp_t flags)
+{
+ struct isp1760_qh *qh;
+
+ qh = kmem_cache_zalloc(qh_cachep, flags);
+ if (!qh)
+ return qh;
+
+ INIT_LIST_HEAD(&qh->qtd_list);
+ qh->priv = priv;
+ return qh;
+}
+
+/* magic numbers that can affect system performance */
+#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
+#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
+#define EHCI_TUNE_RL_TT 0
+#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
+#define EHCI_TUNE_MULT_TT 1
+#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
+
+/* one-time init, only for memory state */
+static int priv_init(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 hcc_params;
+
+ spin_lock_init(&priv->lock);
+
+ /*
+ * hw default: 1K periodic list heads, one per frame.
+ * periodic_size can shrink by USBCMD update if hcc_params allows.
+ */
+ priv->periodic_size = DEFAULT_I_TDPS;
+
+ /* controllers may cache some of the periodic schedule ... */
+ hcc_params = isp1760_readl(hcd->regs + HC_HCCPARAMS);
+ /* full frame cache */
+ if (HCC_ISOC_CACHE(hcc_params))
+ priv->i_thresh = 8;
+ else /* N microframes cached */
+ priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+
+ return 0;
+}
+
+static int isp1760_hc_setup(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int result;
+ u32 scratch;
+
+ isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG);
+ scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG);
+ if (scratch != 0xdeadbabe) {
+ printk(KERN_ERR "ISP1760: Scratch test failed.\n");
+ return -ENODEV;
+ }
+
+ /* pre reset */
+ isp1760_init_regs(hcd);
+
+ /* reset */
+ isp1760_writel(SW_RESET_RESET_ALL, hcd->regs + HC_RESET_REG);
+ mdelay(100);
+
+ isp1760_writel(SW_RESET_RESET_HC, hcd->regs + HC_RESET_REG);
+ mdelay(100);
+
+ result = ehci_reset(priv);
+ if (result)
+ return result;
+
+ /* Step 11 passed */
+
+ isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG);
+ isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE);
+
+ /* ATL reset */
+ scratch = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
+ isp1760_writel(scratch | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL);
+ mdelay(10);
+ isp1760_writel(scratch, hcd->regs + HC_HW_MODE_CTRL);
+
+ isp1760_writel(PORT1_POWER | PORT1_INIT2, hcd->regs + HC_PORT1_CTRL);
+ mdelay(10);
+
+ priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS);
+
+ return priv_init(hcd);
+}
+
+static void isp1760_init_maps(struct usb_hcd *hcd)
+{
+ /*set last maps, for iso its only 1, else 32 tds bitmap*/
+ isp1760_writel(0x80000000, hcd->regs + HC_ATL_PTD_LASTPTD_REG);
+ isp1760_writel(0x80000000, hcd->regs + HC_INT_PTD_LASTPTD_REG);
+ isp1760_writel(0x00000001, hcd->regs + HC_ISO_PTD_LASTPTD_REG);
+}
+
+static void isp1760_enable_interrupts(struct usb_hcd *hcd)
+{
+ isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_AND_REG);
+ isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+ isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_AND_REG);
+ isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+ isp1760_writel(0, hcd->regs + HC_ISO_IRQ_MASK_AND_REG);
+ isp1760_writel(0xffffffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG);
+ /* step 23 passed */
+}
+
+static int isp1760_run(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int retval;
+ u32 temp;
+ u32 command;
+ u32 chipid;
+
+ hcd->uses_new_polling = 1;
+ hcd->poll_rh = 0;
+
+ hcd->state = HC_STATE_RUNNING;
+ isp1760_enable_interrupts(hcd);
+ temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
+ temp |= FINAL_HW_CONFIG;
+ isp1760_writel(temp, hcd->regs + HC_HW_MODE_CTRL);
+
+ command = isp1760_readl(hcd->regs + HC_USBCMD);
+ command &= ~(CMD_LRESET|CMD_RESET);
+ command |= CMD_RUN;
+ isp1760_writel(command, hcd->regs + HC_USBCMD);
+
+ retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN,
+ 250 * 1000);
+ if (retval)
+ return retval;
+
+ /*
+ * XXX
+ * Spec says to write FLAG_CF as last config action, priv code grabs
+ * the semaphore while doing so.
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+ isp1760_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG);
+
+ retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF,
+ 250 * 1000);
+ up_write(&ehci_cf_port_reset_rwsem);
+ if (retval)
+ return retval;
+
+ chipid = isp1760_readl(hcd->regs + HC_CHIP_ID_REG);
+ isp1760_info(priv, "USB ISP %04x HW rev. %d started\n", chipid & 0xffff,
+ chipid >> 16);
+
+ /* PTD Register Init Part 2, Step 28 */
+ /* enable INTs */
+ isp1760_init_maps(hcd);
+
+ /* GRR this is run-once init(), being done every time the HC starts.
+ * So long as they're part of class devices, we can't do it init()
+ * since the class device isn't created that early.
+ */
+ return 0;
+}
+
+static u32 base_to_chip(u32 base)
+{
+ return ((base - 0x400) >> 3);
+}
+
+static void transform_into_atl(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct urb *urb,
+ u32 payload, struct ptd *ptd)
+{
+ u32 dw0;
+ u32 dw1;
+ u32 dw2;
+ u32 dw3;
+ u32 maxpacket;
+ u32 multi;
+ u32 pid_code;
+ u32 rl = RL_COUNTER;
+ u32 nak = NAK_COUNTER;
+
+ /* according to 3.6.2, max packet len can not be > 0x400 */
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ multi = 1 + ((maxpacket >> 11) & 0x3);
+ maxpacket &= 0x7ff;
+
+ /* DW0 */
+ dw0 = PTD_VALID;
+ dw0 |= PTD_LENGTH(qtd->length);
+ dw0 |= PTD_MAXPACKET(maxpacket);
+ dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe));
+ dw1 = usb_pipeendpoint(urb->pipe) >> 1;
+
+ /* DW1 */
+ dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe));
+
+ pid_code = qtd->packet_type;
+ dw1 |= PTD_PID_TOKEN(pid_code);
+
+ if (usb_pipebulk(urb->pipe))
+ dw1 |= PTD_TRANS_BULK;
+ else if (usb_pipeint(urb->pipe))
+ dw1 |= PTD_TRANS_INT;
+
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /* split transaction */
+
+ dw1 |= PTD_TRANS_SPLIT;
+ if (urb->dev->speed == USB_SPEED_LOW)
+ dw1 |= PTD_SE_USB_LOSPEED;
+
+ dw1 |= PTD_PORT_NUM(urb->dev->ttport);
+ dw1 |= PTD_HUB_NUM(urb->dev->tt->hub->devnum);
+
+ /* SE bit for Split INT transfers */
+ if (usb_pipeint(urb->pipe) &&
+ (urb->dev->speed == USB_SPEED_LOW))
+ dw1 |= 2 << 16;
+
+ dw3 = 0;
+ rl = 0;
+ nak = 0;
+ } else {
+ dw0 |= PTD_MULTI(multi);
+ if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe))
+ dw3 = qh->ping;
+ else
+ dw3 = 0;
+ }
+ /* DW2 */
+ dw2 = 0;
+ dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload));
+ dw2 |= PTD_RL_CNT(rl);
+ dw3 |= PTD_NAC_CNT(nak);
+
+ /* DW3 */
+ if (usb_pipecontrol(urb->pipe))
+ dw3 |= PTD_DATA_TOGGLE(qtd->toggle);
+ else
+ dw3 |= qh->toggle;
+
+
+ dw3 |= PTD_ACTIVE;
+ /* Cerr */
+ dw3 |= PTD_CERR(ERR_COUNTER);
+
+ memset(ptd, 0, sizeof(*ptd));
+
+ ptd->dw0 = cpu_to_le32(dw0);
+ ptd->dw1 = cpu_to_le32(dw1);
+ ptd->dw2 = cpu_to_le32(dw2);
+ ptd->dw3 = cpu_to_le32(dw3);
+}
+
+static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct urb *urb,
+ u32 payload, struct ptd *ptd)
+{
+ u32 maxpacket;
+ u32 multi;
+ u32 numberofusofs;
+ u32 i;
+ u32 usofmask, usof;
+ u32 period;
+
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ multi = 1 + ((maxpacket >> 11) & 0x3);
+ maxpacket &= 0x7ff;
+ /* length of the data per uframe */
+ maxpacket = multi * maxpacket;
+
+ numberofusofs = urb->transfer_buffer_length / maxpacket;
+ if (urb->transfer_buffer_length % maxpacket)
+ numberofusofs += 1;
+
+ usofmask = 1;
+ usof = 0;
+ for (i = 0; i < numberofusofs; i++) {
+ usof |= usofmask;
+ usofmask <<= 1;
+ }
+
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /* split */
+ ptd->dw5 = __constant_cpu_to_le32(0x1c);
+
+ if (qh->period >= 32)
+ period = qh->period / 2;
+ else
+ period = qh->period;
+
+ } else {
+
+ if (qh->period >= 8)
+ period = qh->period/8;
+ else
+ period = qh->period;
+
+ if (period >= 32)
+ period = 16;
+
+ if (qh->period >= 8) {
+ /* millisecond period */
+ period = (period << 3);
+ } else {
+ /* usof based tranmsfers */
+ /* minimum 4 usofs */
+ usof = 0x11;
+ }
+ }
+
+ ptd->dw2 |= cpu_to_le32(period);
+ ptd->dw4 = cpu_to_le32(usof);
+}
+
+static void transform_into_int(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct urb *urb,
+ u32 payload, struct ptd *ptd)
+{
+ transform_into_atl(priv, qh, qtd, urb, payload, ptd);
+ transform_add_int(priv, qh, qtd, urb, payload, ptd);
+}
+
+static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len,
+ u32 token)
+{
+ int count;
+
+ qtd->data_buffer = databuffer;
+ qtd->packet_type = GET_QTD_TOKEN_TYPE(token);
+ qtd->toggle = GET_DATA_TOGGLE(token);
+
+ if (len > HC_ATL_PL_SIZE)
+ count = HC_ATL_PL_SIZE;
+ else
+ count = len;
+
+ qtd->length = count;
+ return count;
+}
+
+static int check_error(struct ptd *ptd)
+{
+ int error = 0;
+ u32 dw3;
+
+ dw3 = le32_to_cpu(ptd->dw3);
+ if (dw3 & DW3_HALT_BIT)
+ error = -EPIPE;
+
+ if (dw3 & DW3_ERROR_BIT) {
+ printk(KERN_ERR "error bit is set in DW3\n");
+ error = -EPIPE;
+ }
+
+ if (dw3 & DW3_QTD_ACTIVE) {
+ printk(KERN_ERR "transfer active bit is set DW3\n");
+ printk(KERN_ERR "nak counter: %d, rl: %d\n", (dw3 >> 19) & 0xf,
+ (le32_to_cpu(ptd->dw2) >> 25) & 0xf);
+ }
+
+ return error;
+}
+
+static void check_int_err_status(u32 dw4)
+{
+ u32 i;
+
+ dw4 >>= 8;
+
+ for (i = 0; i < 8; i++) {
+ switch (dw4 & 0x7) {
+ case INT_UNDERRUN:
+ printk(KERN_ERR "ERROR: under run , %d\n", i);
+ break;
+
+ case INT_EXACT:
+ printk(KERN_ERR "ERROR: transaction error, %d\n", i);
+ break;
+
+ case INT_BABBLE:
+ printk(KERN_ERR "ERROR: babble error, %d\n", i);
+ break;
+ }
+ dw4 >>= 3;
+ }
+}
+
+static void enqueue_one_qtd(struct isp1760_qtd *qtd, struct isp1760_hcd *priv,
+ u32 payload)
+{
+ u32 token;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+
+ token = qtd->packet_type;
+
+ if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) {
+ switch (token) {
+ case IN_PID:
+ break;
+ case OUT_PID:
+ case SETUP_PID:
+ priv_write_copy(priv, qtd->data_buffer,
+ hcd->regs + payload,
+ qtd->length);
+ }
+ }
+}
+
+static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload,
+ struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct urb *urb, u32 slot, struct isp1760_qtd *qtd)
+{
+ struct ptd ptd;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+
+ transform_into_atl(priv, qh, qtd, urb, payload, &ptd);
+ priv_write_copy(priv, (u32 *)&ptd, hcd->regs + atl_regs, sizeof(ptd));
+ enqueue_one_qtd(qtd, priv, payload);
+
+ priv->atl_ints[slot].urb = urb;
+ priv->atl_ints[slot].qh = qh;
+ priv->atl_ints[slot].qtd = qtd;
+ priv->atl_ints[slot].data_buffer = qtd->data_buffer;
+ priv->atl_ints[slot].payload = payload;
+ qtd->status |= URB_ENQUEUED | URB_TYPE_ATL;
+ qtd->status |= slot << 16;
+}
+
+static void enqueue_one_int_qtd(u32 int_regs, u32 payload,
+ struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct urb *urb, u32 slot, struct isp1760_qtd *qtd)
+{
+ struct ptd ptd;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+
+ transform_into_int(priv, qh, qtd, urb, payload, &ptd);
+ priv_write_copy(priv, (u32 *)&ptd, hcd->regs + int_regs, sizeof(ptd));
+ enqueue_one_qtd(qtd, priv, payload);
+
+ priv->int_ints[slot].urb = urb;
+ priv->int_ints[slot].qh = qh;
+ priv->int_ints[slot].qtd = qtd;
+ priv->int_ints[slot].data_buffer = qtd->data_buffer;
+ priv->int_ints[slot].payload = payload;
+ qtd->status |= URB_ENQUEUED | URB_TYPE_INT;
+ qtd->status |= slot << 16;
+}
+
+void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 skip_map, or_map;
+ u32 queue_entry;
+ u32 slot;
+ u32 atl_regs, payload;
+ u32 buffstatus;
+
+ skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+ BUG_ON(!skip_map);
+ slot = __ffs(skip_map);
+ queue_entry = 1 << slot;
+
+ atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd);
+
+ payload = alloc_mem(priv, qtd->length);
+
+ enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot, qtd);
+
+ or_map = isp1760_readl(hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+ or_map |= queue_entry;
+ isp1760_writel(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+ skip_map &= ~queue_entry;
+ isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+ buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG);
+ buffstatus |= ATL_BUFFER;
+ isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 skip_map, or_map;
+ u32 queue_entry;
+ u32 slot;
+ u32 int_regs, payload;
+ u32 buffstatus;
+
+ skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+ BUG_ON(!skip_map);
+ slot = __ffs(skip_map);
+ queue_entry = 1 << slot;
+
+ int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd);
+
+ payload = alloc_mem(priv, qtd->length);
+
+ enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot, qtd);
+
+ or_map = isp1760_readl(hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+ or_map |= queue_entry;
+ isp1760_writel(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+ skip_map &= ~queue_entry;
+ isp1760_writel(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+ buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG);
+ buffstatus |= INT_BUFFER;
+ isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+static void isp1760_urb_done(struct isp1760_hcd *priv, struct urb *urb, int status)
+__releases(priv->lock)
+__acquires(priv->lock)
+{
+ if (!urb->unlinked) {
+ if (status == -EINPROGRESS)
+ status = 0;
+ }
+
+ /* complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+ spin_unlock(&priv->lock);
+ usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status);
+ spin_lock(&priv->lock);
+}
+
+static void isp1760_qtd_free(struct isp1760_qtd *qtd)
+{
+ kmem_cache_free(qtd_cachep, qtd);
+}
+
+static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd)
+{
+ struct isp1760_qtd *tmp_qtd;
+
+ tmp_qtd = qtd->hw_next;
+ list_del(&qtd->qtd_list);
+ isp1760_qtd_free(qtd);
+ return tmp_qtd;
+}
+
+/*
+ * Remove this QTD from the QH list and free its memory. If this QTD
+ * isn't the last one than remove also his successor(s).
+ * Returns the QTD which is part of an new URB and should be enqueued.
+ */
+static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd)
+{
+ struct isp1760_qtd *tmp_qtd;
+ int last_one;
+
+ do {
+ tmp_qtd = qtd->hw_next;
+ last_one = qtd->status & URB_COMPLETE_NOTIFY;
+ list_del(&qtd->qtd_list);
+ isp1760_qtd_free(qtd);
+ qtd = tmp_qtd;
+ } while (!last_one && qtd);
+
+ return qtd;
+}
+
+static void do_atl_int(struct usb_hcd *usb_hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ u32 done_map, skip_map;
+ struct ptd ptd;
+ struct urb *urb = NULL;
+ u32 atl_regs_base;
+ u32 atl_regs;
+ u32 queue_entry;
+ u32 payload;
+ u32 length;
+ u32 or_map;
+ u32 status = -EINVAL;
+ int error;
+ struct isp1760_qtd *qtd;
+ struct isp1760_qh *qh;
+ u32 rl;
+ u32 nakcount;
+
+ done_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_PTD_DONEMAP_REG);
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+
+ or_map = isp1760_readl(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+ or_map &= ~done_map;
+ isp1760_writel(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+ atl_regs_base = ATL_REGS_OFFSET;
+ while (done_map) {
+ u32 dw1;
+ u32 dw2;
+ u32 dw3;
+
+ status = 0;
+
+ queue_entry = __ffs(done_map);
+ done_map &= ~(1 << queue_entry);
+ skip_map |= 1 << queue_entry;
+
+ atl_regs = atl_regs_base + queue_entry * sizeof(struct ptd);
+
+ urb = priv->atl_ints[queue_entry].urb;
+ qtd = priv->atl_ints[queue_entry].qtd;
+ qh = priv->atl_ints[queue_entry].qh;
+ payload = priv->atl_ints[queue_entry].payload;
+
+ if (!qh) {
+ printk(KERN_ERR "qh is 0\n");
+ continue;
+ }
+ priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs,
+ atl_regs, sizeof(ptd));
+
+ dw1 = le32_to_cpu(ptd.dw1);
+ dw2 = le32_to_cpu(ptd.dw2);
+ dw3 = le32_to_cpu(ptd.dw3);
+ rl = (dw2 >> 25) & 0x0f;
+ nakcount = (dw3 >> 19) & 0xf;
+
+ /* Transfer Error, *but* active and no HALT -> reload */
+ if ((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) &&
+ !(dw3 & DW3_HALT_BIT)) {
+
+ /* according to ppriv code, we have to
+ * reload this one if trasfered bytes != requested bytes
+ * else act like everything went smooth..
+ * XXX This just doesn't feel right and hasn't
+ * triggered so far.
+ */
+
+ length = PTD_XFERRED_LENGTH(dw3);
+ printk(KERN_ERR "Should reload now.... transfered %d "
+ "of %zu\n", length, qtd->length);
+ BUG();
+ }
+
+ if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) {
+ u32 buffstatus;
+
+ /* XXX
+ * NAKs are handled in HW by the chip. Usually if the
+ * device is not able to send data fast enough.
+ * This did not trigger for a long time now.
+ */
+ printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: "
+ "%d of %d done: %08x cur: %08x\n", qtd,
+ urb, qh, PTD_XFERRED_LENGTH(dw3),
+ qtd->length, done_map,
+ (1 << queue_entry));
+
+ /* RL counter = ERR counter */
+ dw3 &= ~(0xf << 19);
+ dw3 |= rl << 19;
+ dw3 &= ~(3 << (55 - 32));
+ dw3 |= ERR_COUNTER << (55 - 32);
+
+ /*
+ * It is not needed to write skip map back because it
+ * is unchanged. Just make sure that this entry is
+ * unskipped once it gets written to the HW.
+ */
+ skip_map &= ~(1 << queue_entry);
+ or_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_IRQ_MASK_OR_REG);
+ or_map |= 1 << queue_entry;
+ isp1760_writel(or_map, usb_hcd->regs +
+ HC_ATL_IRQ_MASK_OR_REG);
+
+ ptd.dw3 = cpu_to_le32(dw3);
+ priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
+ atl_regs, sizeof(ptd));
+
+ ptd.dw0 |= __constant_cpu_to_le32(PTD_VALID);
+ priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
+ atl_regs, sizeof(ptd));
+
+ buffstatus = isp1760_readl(usb_hcd->regs +
+ HC_BUFFER_STATUS_REG);
+ buffstatus |= ATL_BUFFER;
+ isp1760_writel(buffstatus, usb_hcd->regs +
+ HC_BUFFER_STATUS_REG);
+ continue;
+ }
+
+ error = check_error(&ptd);
+ if (error) {
+ status = error;
+ priv->atl_ints[queue_entry].qh->toggle = 0;
+ priv->atl_ints[queue_entry].qh->ping = 0;
+ urb->status = -EPIPE;
+
+#if 0
+ printk(KERN_ERR "Error in %s().\n", __func__);
+ printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
+ "dw3: %08x dw4: %08x dw5: %08x dw6: "
+ "%08x dw7: %08x\n",
+ ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
+ ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
+#endif
+ } else {
+ if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+ priv->atl_ints[queue_entry].qh->toggle = dw3 &
+ (1 << 25);
+ priv->atl_ints[queue_entry].qh->ping = dw3 &
+ (1 << 26);
+ }
+ }
+
+ length = PTD_XFERRED_LENGTH(dw3);
+ if (length) {
+ switch (DW1_GET_PID(dw1)) {
+ case IN_PID:
+ priv_read_copy(priv,
+ priv->atl_ints[queue_entry].data_buffer,
+ usb_hcd->regs + payload, payload,
+ length);
+
+ case OUT_PID:
+
+ urb->actual_length += length;
+
+ case SETUP_PID:
+ break;
+ }
+ }
+
+ priv->atl_ints[queue_entry].data_buffer = NULL;
+ priv->atl_ints[queue_entry].urb = NULL;
+ priv->atl_ints[queue_entry].qtd = NULL;
+ priv->atl_ints[queue_entry].qh = NULL;
+
+ free_mem(priv, payload);
+
+ isp1760_writel(skip_map, usb_hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+
+ if (urb->status == -EPIPE) {
+ /* HALT was received */
+
+ qtd = clean_up_qtdlist(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) {
+ /* short BULK received */
+
+ printk(KERN_ERR "short bulk, %d instead %d\n", length,
+ qtd->length);
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ urb->status = -EREMOTEIO;
+ printk(KERN_ERR "not okey\n");
+ }
+
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+
+ qtd = clean_up_qtdlist(qtd);
+
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else if (qtd->status & URB_COMPLETE_NOTIFY) {
+ /* that was the last qtd of that URB */
+
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+
+ qtd = clean_this_qtd(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else {
+ /* next QTD of this URB */
+
+ qtd = clean_this_qtd(qtd);
+ BUG_ON(!qtd);
+ }
+
+ if (qtd)
+ enqueue_an_ATL_packet(usb_hcd, qh, qtd);
+
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+ }
+}
+
+static void do_intl_int(struct usb_hcd *usb_hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ u32 done_map, skip_map;
+ struct ptd ptd;
+ struct urb *urb = NULL;
+ u32 int_regs;
+ u32 int_regs_base;
+ u32 payload;
+ u32 length;
+ u32 or_map;
+ int error;
+ u32 queue_entry;
+ struct isp1760_qtd *qtd;
+ struct isp1760_qh *qh;
+
+ done_map = isp1760_readl(usb_hcd->regs +
+ HC_INT_PTD_DONEMAP_REG);
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+
+ or_map = isp1760_readl(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+ or_map &= ~done_map;
+ isp1760_writel(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+ int_regs_base = INT_REGS_OFFSET;
+
+ while (done_map) {
+ u32 dw1;
+ u32 dw3;
+
+ queue_entry = __ffs(done_map);
+ done_map &= ~(1 << queue_entry);
+ skip_map |= 1 << queue_entry;
+
+ int_regs = int_regs_base + queue_entry * sizeof(struct ptd);
+ urb = priv->int_ints[queue_entry].urb;
+ qtd = priv->int_ints[queue_entry].qtd;
+ qh = priv->int_ints[queue_entry].qh;
+ payload = priv->int_ints[queue_entry].payload;
+
+ if (!qh) {
+ printk(KERN_ERR "(INT) qh is 0\n");
+ continue;
+ }
+
+ priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs,
+ int_regs, sizeof(ptd));
+ dw1 = le32_to_cpu(ptd.dw1);
+ dw3 = le32_to_cpu(ptd.dw3);
+ check_int_err_status(le32_to_cpu(ptd.dw4));
+
+ error = check_error(&ptd);
+ if (error) {
+#if 0
+ printk(KERN_ERR "Error in %s().\n", __func__);
+ printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
+ "dw3: %08x dw4: %08x dw5: %08x dw6: "
+ "%08x dw7: %08x\n",
+ ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
+ ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
+#endif
+ urb->status = -EPIPE;
+ priv->int_ints[queue_entry].qh->toggle = 0;
+ priv->int_ints[queue_entry].qh->ping = 0;
+
+ } else {
+ priv->int_ints[queue_entry].qh->toggle =
+ dw3 & (1 << 25);
+ priv->int_ints[queue_entry].qh->ping = dw3 & (1 << 26);
+ }
+
+ if (urb->dev->speed != USB_SPEED_HIGH)
+ length = PTD_XFERRED_LENGTH_LO(dw3);
+ else
+ length = PTD_XFERRED_LENGTH(dw3);
+
+ if (length) {
+ switch (DW1_GET_PID(dw1)) {
+ case IN_PID:
+ priv_read_copy(priv,
+ priv->int_ints[queue_entry].data_buffer,
+ usb_hcd->regs + payload , payload,
+ length);
+ case OUT_PID:
+
+ urb->actual_length += length;
+
+ case SETUP_PID:
+ break;
+ }
+ }
+
+ priv->int_ints[queue_entry].data_buffer = NULL;
+ priv->int_ints[queue_entry].urb = NULL;
+ priv->int_ints[queue_entry].qtd = NULL;
+ priv->int_ints[queue_entry].qh = NULL;
+
+ isp1760_writel(skip_map, usb_hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+ free_mem(priv, payload);
+
+ if (urb->status == -EPIPE) {
+ /* HALT received */
+
+ qtd = clean_up_qtdlist(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else if (qtd->status & URB_COMPLETE_NOTIFY) {
+
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+
+ qtd = clean_this_qtd(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else {
+ /* next QTD of this URB */
+
+ qtd = clean_this_qtd(qtd);
+ BUG_ON(!qtd);
+ }
+
+ if (qtd)
+ enqueue_an_INT_packet(usb_hcd, qh, qtd);
+
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+ }
+}
+
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+static struct isp1760_qh *qh_make(struct isp1760_hcd *priv, struct urb *urb,
+ gfp_t flags)
+{
+ struct isp1760_qh *qh;
+ int is_input, type;
+
+ qh = isp1760_qh_alloc(priv, flags);
+ if (!qh)
+ return qh;
+
+ /*
+ * init endpoint/device data for this QH
+ */
+ is_input = usb_pipein(urb->pipe);
+ type = usb_pipetype(urb->pipe);
+
+ if (type == PIPE_INTERRUPT) {
+
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+
+ qh->period = urb->interval >> 3;
+ if (qh->period == 0 && urb->interval != 1) {
+ /* NOTE interval 2 or 4 uframes could work.
+ * But interval 1 scheduling is simpler, and
+ * includes high bandwidth.
+ */
+ printk(KERN_ERR "intr period %d uframes, NYET!",
+ urb->interval);
+ qh_destroy(qh);
+ return NULL;
+ }
+ } else {
+ qh->period = urb->interval;
+ }
+ }
+
+ /* support for tt scheduling, and access to toggles */
+ qh->dev = urb->dev;
+
+ if (!usb_pipecontrol(urb->pipe))
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input,
+ 1);
+ return qh;
+}
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct isp1760_qh *qh_append_tds(struct isp1760_hcd *priv,
+ struct urb *urb, struct list_head *qtd_list, int epnum,
+ void **ptr)
+{
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+ struct isp1760_qtd *prev_qtd;
+
+ qh = (struct isp1760_qh *)*ptr;
+ if (!qh) {
+ /* can't sleep here, we have priv->lock... */
+ qh = qh_make(priv, urb, GFP_ATOMIC);
+ if (!qh)
+ return qh;
+ *ptr = qh;
+ }
+
+ qtd = list_entry(qtd_list->next, struct isp1760_qtd,
+ qtd_list);
+ if (!list_empty(&qh->qtd_list))
+ prev_qtd = list_entry(qh->qtd_list.prev,
+ struct isp1760_qtd, qtd_list);
+ else
+ prev_qtd = NULL;
+
+ list_splice(qtd_list, qh->qtd_list.prev);
+ if (prev_qtd) {
+ BUG_ON(prev_qtd->hw_next);
+ prev_qtd->hw_next = qtd;
+ }
+
+ urb->hcpriv = qh;
+ return qh;
+}
+
+static void qtd_list_free(struct isp1760_hcd *priv, struct urb *urb,
+ struct list_head *qtd_list)
+{
+ struct list_head *entry, *temp;
+
+ list_for_each_safe(entry, temp, qtd_list) {
+ struct isp1760_qtd *qtd;
+
+ qtd = list_entry(entry, struct isp1760_qtd, qtd_list);
+ list_del(&qtd->qtd_list);
+ isp1760_qtd_free(qtd);
+ }
+}
+
+static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb,
+ struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p)
+{
+ struct isp1760_qtd *qtd;
+ int epnum;
+ unsigned long flags;
+ struct isp1760_qh *qh = NULL;
+ int rc;
+ int qh_busy;
+
+ qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list);
+ epnum = urb->ep->desc.bEndpointAddress;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) {
+ rc = -ESHUTDOWN;
+ goto done;
+ }
+ rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb);
+ if (rc)
+ goto done;
+
+ qh = urb->ep->hcpriv;
+ if (qh)
+ qh_busy = !list_empty(&qh->qtd_list);
+ else
+ qh_busy = 0;
+
+ qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv);
+ if (!qh) {
+ usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ if (!qh_busy)
+ p(priv_to_hcd(priv), qh, qtd);
+
+done:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (!qh)
+ qtd_list_free(priv, urb, qtd_list);
+ return rc;
+}
+
+static struct isp1760_qtd *isp1760_qtd_alloc(struct isp1760_hcd *priv,
+ gfp_t flags)
+{
+ struct isp1760_qtd *qtd;
+
+ qtd = kmem_cache_zalloc(qtd_cachep, flags);
+ if (qtd)
+ INIT_LIST_HEAD(&qtd->qtd_list);
+
+ return qtd;
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv,
+ struct urb *urb, struct list_head *head, gfp_t flags)
+{
+ struct isp1760_qtd *qtd, *qtd_prev;
+ void *buf;
+ int len, maxpacket;
+ int is_input;
+ u32 token;
+
+ /*
+ * URBs map to sequences of QTDs: one logical transaction
+ */
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ return NULL;
+
+ list_add_tail(&qtd->qtd_list, head);
+ qtd->urb = urb;
+ urb->status = -EINPROGRESS;
+
+ token = 0;
+ /* for split transactions, SplitXState initialized to zero */
+
+ len = urb->transfer_buffer_length;
+ is_input = usb_pipein(urb->pipe);
+ if (usb_pipecontrol(urb->pipe)) {
+ /* SETUP pid */
+ qtd_fill(qtd, urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ token | SETUP_PID);
+
+ /* ... and always at least one more pid */
+ token ^= DATA_TOGGLE;
+ qtd_prev = qtd;
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = qtd;
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* for zero length DATA stages, STATUS is always IN */
+ if (len == 0)
+ token |= IN_PID;
+ }
+
+ /*
+ * data transfer stage: buffer setup
+ */
+ buf = urb->transfer_buffer;
+
+ if (is_input)
+ token |= IN_PID;
+ else
+ token |= OUT_PID;
+
+ maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+ /*
+ * buffer gets wrapped in one or more qtds;
+ * last one may be "short" (including zero len)
+ * and may serve as a control status ack
+ */
+ for (;;) {
+ int this_qtd_len;
+
+ if (!buf && len) {
+ /* XXX This looks like usb storage / SCSI bug */
+ printk(KERN_ERR "buf is null, dma is %08lx len is %d\n",
+ (long unsigned)urb->transfer_dma, len);
+ WARN_ON(1);
+ }
+
+ this_qtd_len = qtd_fill(qtd, buf, len, token);
+ len -= this_qtd_len;
+ buf += this_qtd_len;
+
+ /* qh makes control packets use qtd toggle; maybe switch it */
+ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+ token ^= DATA_TOGGLE;
+
+ if (len <= 0)
+ break;
+
+ qtd_prev = qtd;
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = qtd;
+ list_add_tail(&qtd->qtd_list, head);
+ }
+
+ /*
+ * control requests may need a terminating data "status" ack;
+ * bulk ones may need a terminating short packet (zero length).
+ */
+ if (urb->transfer_buffer_length != 0) {
+ int one_more = 0;
+
+ if (usb_pipecontrol(urb->pipe)) {
+ one_more = 1;
+ /* "in" <--> "out" */
+ token ^= IN_PID;
+ /* force DATA1 */
+ token |= DATA_TOGGLE;
+ } else if (usb_pipebulk(urb->pipe)
+ && (urb->transfer_flags & URB_ZERO_PACKET)
+ && !(urb->transfer_buffer_length % maxpacket)) {
+ one_more = 1;
+ }
+ if (one_more) {
+ qtd_prev = qtd;
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = qtd;
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* never any data in such packets */
+ qtd_fill(qtd, NULL, 0, token);
+ }
+ }
+
+ qtd->status = URB_COMPLETE_NOTIFY;
+ return head;
+
+cleanup:
+ qtd_list_free(priv, urb, head);
+ return NULL;
+}
+
+static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct list_head qtd_list;
+ packet_enqueue *pe;
+
+ INIT_LIST_HEAD(&qtd_list);
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+
+ if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ pe = enqueue_an_ATL_packet;
+ break;
+
+ case PIPE_INTERRUPT:
+ if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ pe = enqueue_an_INT_packet;
+ break;
+
+ case PIPE_ISOCHRONOUS:
+ printk(KERN_ERR "PIPE_ISOCHRONOUS ain't supported\n");
+ default:
+ return -EPIPE;
+ }
+
+ isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe);
+ return 0;
+}
+
+static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct inter_packet_info *ints;
+ u32 i;
+ u32 reg_base, or_reg, skip_reg;
+ int flags;
+ struct ptd ptd;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_ISOCHRONOUS:
+ return -EPIPE;
+ break;
+
+ case PIPE_INTERRUPT:
+ ints = priv->int_ints;
+ reg_base = INT_REGS_OFFSET;
+ or_reg = HC_INT_IRQ_MASK_OR_REG;
+ skip_reg = HC_INT_PTD_SKIPMAP_REG;
+ break;
+
+ default:
+ ints = priv->atl_ints;
+ reg_base = ATL_REGS_OFFSET;
+ or_reg = HC_ATL_IRQ_MASK_OR_REG;
+ skip_reg = HC_ATL_PTD_SKIPMAP_REG;
+ break;
+ }
+
+ memset(&ptd, 0, sizeof(ptd));
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for (i = 0; i < 32; i++) {
+ if (ints->urb == urb) {
+ u32 skip_map;
+ u32 or_map;
+ struct isp1760_qtd *qtd;
+
+ skip_map = isp1760_readl(hcd->regs + skip_reg);
+ skip_map |= 1 << i;
+ isp1760_writel(skip_map, hcd->regs + skip_reg);
+
+ or_map = isp1760_readl(hcd->regs + or_reg);
+ or_map &= ~(1 << i);
+ isp1760_writel(or_map, hcd->regs + or_reg);
+
+ priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base
+ + i * sizeof(ptd), sizeof(ptd));
+ qtd = ints->qtd;
+
+ clean_up_qtdlist(qtd);
+
+ free_mem(priv, ints->payload);
+
+ ints->urb = NULL;
+ ints->qh = NULL;
+ ints->qtd = NULL;
+ ints->data_buffer = NULL;
+ ints->payload = 0;
+
+ isp1760_urb_done(priv, urb, status);
+ break;
+ }
+ ints++;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+}
+
+static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ u32 imask;
+ irqreturn_t irqret = IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ if (!(usb_hcd->state & HC_STATE_RUNNING))
+ goto leave;
+
+ imask = isp1760_readl(usb_hcd->regs + HC_INTERRUPT_REG);
+ if (unlikely(!imask))
+ goto leave;
+
+ isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG);
+ if (imask & HC_ATL_INT)
+ do_atl_int(usb_hcd);
+
+ if (imask & HC_INTL_INT)
+ do_intl_int(usb_hcd);
+
+ irqret = IRQ_HANDLED;
+leave:
+ spin_unlock(&priv->lock);
+ return irqret;
+}
+
+static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 temp, status = 0;
+ u32 mask;
+ int retval = 1;
+ unsigned long flags;
+
+ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ if (!HC_IS_RUNNING(hcd->state))
+ return 0;
+
+ /* init status to no-changes */
+ buf[0] = 0;
+ mask = PORT_CSC;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ temp = isp1760_readl(hcd->regs + HC_PORTSC1);
+
+ if (temp & PORT_OWNER) {
+ if (temp & PORT_CSC) {
+ temp &= ~PORT_CSC;
+ isp1760_writel(temp, hcd->regs + HC_PORTSC1);
+ goto done;
+ }
+ }
+
+ /*
+ * Return status information even for ports with OWNER set.
+ * Otherwise khubd wouldn't see the disconnect event when a
+ * high-speed device is switched over to the companion
+ * controller by the user.
+ */
+
+ if ((temp & mask) != 0
+ || ((temp & PORT_RESUME) != 0
+ && time_after_eq(jiffies,
+ priv->reset_done))) {
+ buf [0] |= 1 << (0 + 1);
+ status = STS_PCD;
+ }
+ /* FIXME autosuspend idle root hubs */
+done:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return status ? retval : 0;
+}
+
+static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+ struct usb_hub_descriptor *desc)
+{
+ int ports = HCS_N_PORTS(priv->hcs_params);
+ u16 temp;
+
+ desc->bDescriptorType = 0x29;
+ /* priv 1.0, 2.3.9 says 20ms max */
+ desc->bPwrOn2PwrGood = 10;
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = ports;
+ temp = 1 + (ports / 8);
+ desc->bDescLength = 7 + 2 * temp;
+
+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+ memset(&desc->bitmap[0], 0, temp);
+ memset(&desc->bitmap[temp], 0xff, temp);
+
+ /* per-port overcurrent reporting */
+ temp = 0x0008;
+ if (HCS_PPC(priv->hcs_params))
+ /* per-port power control */
+ temp |= 0x0001;
+ else
+ /* no power switching */
+ temp |= 0x0002;
+ desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+static int check_reset_complete(struct isp1760_hcd *priv, int index,
+ u32 __iomem *status_reg, int port_status)
+{
+ if (!(port_status & PORT_CONNECT))
+ return port_status;
+
+ /* if reset finished and it's still not enabled -- handoff */
+ if (!(port_status & PORT_PE)) {
+
+ printk(KERN_ERR "port %d full speed --> companion\n",
+ index + 1);
+
+ port_status |= PORT_OWNER;
+ port_status &= ~PORT_RWC_BITS;
+ isp1760_writel(port_status, status_reg);
+
+ } else
+ printk(KERN_ERR "port %d high speed\n", index + 1);
+
+ return port_status;
+}
+
+static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int ports = HCS_N_PORTS(priv->hcs_params);
+ u32 __iomem *status_reg = hcd->regs + HC_PORTSC1;
+ u32 temp, status;
+ unsigned long flags;
+ int retval = 0;
+ unsigned selector;
+
+ /*
+ * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+ * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+ * (track current state ourselves) ... blink for diagnostics,
+ * power, "this is the one", etc. EHCI spec supports this.
+ */
+
+ spin_lock_irqsave(&priv->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = isp1760_readl(status_reg);
+
+ /*
+ * Even if OWNER is set, so the port is owned by the
+ * companion controller, khubd needs to be able to clear
+ * the port-change status bits (especially
+ * USB_PORT_FEAT_C_CONNECTION).
+ */
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ isp1760_writel(temp & ~PORT_PE, status_reg);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ /* XXX error? */
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ if (temp & PORT_RESET)
+ goto error;
+
+ if (temp & PORT_SUSPEND) {
+ if ((temp & PORT_PE) == 0)
+ goto error;
+ /* resume signaling for 20 msec */
+ temp &= ~(PORT_RWC_BITS);
+ isp1760_writel(temp | PORT_RESUME,
+ status_reg);
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(20);
+ }
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ /* we auto-clear this feature */
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(priv->hcs_params))
+ isp1760_writel(temp & ~PORT_POWER, status_reg);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ isp1760_writel(temp | PORT_CSC,
+ status_reg);
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ /* XXX error ?*/
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ /* GetPortStatus clears reset */
+ break;
+ default:
+ goto error;
+ }
+ isp1760_readl(hcd->regs + HC_USBCMD);
+ break;
+ case GetHubDescriptor:
+ isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
+ buf);
+ break;
+ case GetHubStatus:
+ /* no hub-wide feature/status flags */
+ memset(buf, 0, 4);
+ break;
+ case GetPortStatus:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ status = 0;
+ temp = isp1760_readl(status_reg);
+
+ /* wPortChange bits */
+ if (temp & PORT_CSC)
+ status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+
+
+ /* whoever resumes must GetPortStatus to complete it!! */
+ if (temp & PORT_RESUME) {
+ printk(KERN_ERR "Port resume should be skipped.\n");
+
+ /* Remote Wakeup received? */
+ if (!priv->reset_done) {
+ /* resume signaling for 20 msec */
+ priv->reset_done = jiffies
+ + msecs_to_jiffies(20);
+ /* check the port again */
+ mod_timer(&priv_to_hcd(priv)->rh_timer,
+ priv->reset_done);
+ }
+
+ /* resume completed? */
+ else if (time_after_eq(jiffies,
+ priv->reset_done)) {
+ status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ priv->reset_done = 0;
+
+ /* stop resume signaling */
+ temp = isp1760_readl(status_reg);
+ isp1760_writel(
+ temp & ~(PORT_RWC_BITS | PORT_RESUME),
+ status_reg);
+ retval = handshake(priv, status_reg,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ isp1760_err(priv,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ }
+ }
+
+ /* whoever resets must GetPortStatus to complete it!! */
+ if ((temp & PORT_RESET)
+ && time_after_eq(jiffies,
+ priv->reset_done)) {
+ status |= 1 << USB_PORT_FEAT_C_RESET;
+ priv->reset_done = 0;
+
+ /* force reset to complete */
+ isp1760_writel(temp & ~PORT_RESET,
+ status_reg);
+ /* REVISIT: some hardware needs 550+ usec to clear
+ * this bit; seems too long to spin routinely...
+ */
+ retval = handshake(priv, status_reg,
+ PORT_RESET, 0, 750);
+ if (retval != 0) {
+ isp1760_err(priv, "port %d reset error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+
+ /* see what we found out */
+ temp = check_reset_complete(priv, wIndex, status_reg,
+ isp1760_readl(status_reg));
+ }
+ /*
+ * Even if OWNER is set, there's no harm letting khubd
+ * see the wPortStatus values (they should all be 0 except
+ * for PORT_POWER anyway).
+ */
+
+ if (temp & PORT_OWNER)
+ printk(KERN_ERR "Warning: PORT_OWNER is set\n");
+
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ /* status may be from integrated TT */
+ status |= ehci_port_speed(priv, temp);
+ }
+ if (temp & PORT_PE)
+ status |= 1 << USB_PORT_FEAT_ENABLE;
+ if (temp & (PORT_SUSPEND|PORT_RESUME))
+ status |= 1 << USB_PORT_FEAT_SUSPEND;
+ if (temp & PORT_RESET)
+ status |= 1 << USB_PORT_FEAT_RESET;
+ if (temp & PORT_POWER)
+ status |= 1 << USB_PORT_FEAT_POWER;
+
+ put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case SetPortFeature:
+ selector = wIndex >> 8;
+ wIndex &= 0xff;
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = isp1760_readl(status_reg);
+ if (temp & PORT_OWNER)
+ break;
+
+/* temp &= ~PORT_RWC_BITS; */
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ isp1760_writel(temp | PORT_PE, status_reg);
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+ if ((temp & PORT_PE) == 0
+ || (temp & PORT_RESET) != 0)
+ goto error;
+
+ isp1760_writel(temp | PORT_SUSPEND, status_reg);
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(priv->hcs_params))
+ isp1760_writel(temp | PORT_POWER,
+ status_reg);
+ break;
+ case USB_PORT_FEAT_RESET:
+ if (temp & PORT_RESUME)
+ goto error;
+ /* line status bits may report this as low speed,
+ * which can be fine if this root hub has a
+ * transaction translator built in.
+ */
+ if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+ && PORT_USB11(temp)) {
+ temp |= PORT_OWNER;
+ } else {
+ temp |= PORT_RESET;
+ temp &= ~PORT_PE;
+
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 spec says 50 ms resets on root
+ */
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(50);
+ }
+ isp1760_writel(temp, status_reg);
+ break;
+ default:
+ goto error;
+ }
+ isp1760_readl(hcd->regs + HC_USBCMD);
+ break;
+
+ default:
+error:
+ /* "stall" on error */
+ retval = -EPIPE;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return retval;
+}
+
+static void isp1760_endpoint_disable(struct usb_hcd *usb_hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+ u32 flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ qh = ep->hcpriv;
+ if (!qh)
+ goto out;
+
+ ep->hcpriv = NULL;
+ do {
+ /* more than entry might get removed */
+ if (list_empty(&qh->qtd_list))
+ break;
+
+ qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd,
+ qtd_list);
+
+ if (qtd->status & URB_ENQUEUED) {
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ isp1760_urb_dequeue(usb_hcd, qtd->urb, -ECONNRESET);
+ spin_lock_irqsave(&priv->lock, flags);
+ } else {
+ struct urb *urb;
+
+ urb = qtd->urb;
+ clean_up_qtdlist(qtd);
+ isp1760_urb_done(priv, urb, -ECONNRESET);
+ }
+ } while (1);
+
+ qh_destroy(qh);
+ /* remove requests and leak them.
+ * ATL are pretty fast done, INT could take a while...
+ * The latter shoule be removed
+ */
+out:
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int isp1760_get_frame(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 fr;
+
+ fr = isp1760_readl(hcd->regs + HC_FRINDEX);
+ return (fr >> 3) % priv->periodic_size;
+}
+
+static void isp1760_stop(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
+ NULL, 0);
+ mdelay(20);
+
+ spin_lock_irq(&priv->lock);
+ ehci_reset(priv);
+ /* Disable IRQ */
+ isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL);
+ spin_unlock_irq(&priv->lock);
+
+ isp1760_writel(0, hcd->regs + HC_CONFIGFLAG);
+}
+
+static void isp1760_shutdown(struct usb_hcd *hcd)
+{
+ u32 command;
+
+ isp1760_stop(hcd);
+ isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL);
+
+ command = isp1760_readl(hcd->regs + HC_USBCMD);
+ command &= ~CMD_RUN;
+ isp1760_writel(command, hcd->regs + HC_USBCMD);
+}
+
+static const struct hc_driver isp1760_hc_driver = {
+ .description = "isp1760-hcd",
+ .product_desc = "NXP ISP1760 USB Host Controller",
+ .hcd_priv_size = sizeof(struct isp1760_hcd),
+ .irq = isp1760_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = isp1760_hc_setup,
+ .start = isp1760_run,
+ .stop = isp1760_stop,
+ .shutdown = isp1760_shutdown,
+ .urb_enqueue = isp1760_urb_enqueue,
+ .urb_dequeue = isp1760_urb_dequeue,
+ .endpoint_disable = isp1760_endpoint_disable,
+ .get_frame_number = isp1760_get_frame,
+ .hub_status_data = isp1760_hub_status_data,
+ .hub_control = isp1760_hub_control,
+};
+
+int __init init_kmem_once(void)
+{
+ qtd_cachep = kmem_cache_create("isp1760_qtd",
+ sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
+ SLAB_MEM_SPREAD, NULL);
+
+ if (!qtd_cachep)
+ return -ENOMEM;
+
+ qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh),
+ 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
+
+ if (!qh_cachep) {
+ kmem_cache_destroy(qtd_cachep);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void deinit_kmem_cache(void)
+{
+ kmem_cache_destroy(qtd_cachep);
+ kmem_cache_destroy(qh_cachep);
+}
+
+struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
+ u64 irqflags, struct device *dev, const char *busname)
+{
+ struct usb_hcd *hcd;
+ struct isp1760_hcd *priv;
+ int ret;
+
+ if (usb_disabled())
+ return ERR_PTR(-ENODEV);
+
+ /* prevent usb-core allocating DMA pages */
+ dev->dma_mask = NULL;
+
+ hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev->bus_id);
+ if (!hcd)
+ return ERR_PTR(-ENOMEM);
+
+ priv = hcd_to_priv(hcd);
+ init_memory(priv);
+ hcd->regs = ioremap(res_start, res_len);
+ if (!hcd->regs) {
+ ret = -EIO;
+ goto err_put;
+ }
+
+ ret = usb_add_hcd(hcd, irq, irqflags);
+ if (ret)
+ goto err_unmap;
+
+ hcd->irq = irq;
+ hcd->rsrc_start = res_start;
+ hcd->rsrc_len = res_len;
+
+ return hcd;
+
+err_unmap:
+ iounmap(hcd->regs);
+
+err_put:
+ usb_put_hcd(hcd);
+
+ return ERR_PTR(ret);
+}
+
+MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
+MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
new file mode 100644
index 00000000000..3d86d0f6b14
--- /dev/null
+++ b/drivers/usb/host/isp1760-hcd.h
@@ -0,0 +1,206 @@
+#ifndef _ISP1760_HCD_H_
+#define _ISP1760_HCD_H_
+
+/* exports for if */
+struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
+ u64 irqflags, struct device *dev, const char *busname);
+int init_kmem_once(void);
+void deinit_kmem_cache(void);
+
+/* EHCI capability registers */
+#define HC_CAPLENGTH 0x00
+#define HC_HCSPARAMS 0x04
+#define HC_HCCPARAMS 0x08
+
+/* EHCI operational registers */
+#define HC_USBCMD 0x20
+#define HC_USBSTS 0x24
+#define HC_FRINDEX 0x2c
+#define HC_CONFIGFLAG 0x60
+#define HC_PORTSC1 0x64
+#define HC_ISO_PTD_DONEMAP_REG 0x130
+#define HC_ISO_PTD_SKIPMAP_REG 0x134
+#define HC_ISO_PTD_LASTPTD_REG 0x138
+#define HC_INT_PTD_DONEMAP_REG 0x140
+#define HC_INT_PTD_SKIPMAP_REG 0x144
+#define HC_INT_PTD_LASTPTD_REG 0x148
+#define HC_ATL_PTD_DONEMAP_REG 0x150
+#define HC_ATL_PTD_SKIPMAP_REG 0x154
+#define HC_ATL_PTD_LASTPTD_REG 0x158
+
+/* Configuration Register */
+#define HC_HW_MODE_CTRL 0x300
+#define ALL_ATX_RESET (1 << 31)
+#define HW_DATA_BUS_32BIT (1 << 8)
+#define HW_DACK_POL_HIGH (1 << 6)
+#define HW_DREQ_POL_HIGH (1 << 5)
+#define HW_INTR_HIGH_ACT (1 << 2)
+#define HW_INTR_EDGE_TRIG (1 << 1)
+#define HW_GLOBAL_INTR_EN (1 << 0)
+
+#define HC_CHIP_ID_REG 0x304
+#define HC_SCRATCH_REG 0x308
+
+#define HC_RESET_REG 0x30c
+#define SW_RESET_RESET_HC (1 << 1)
+#define SW_RESET_RESET_ALL (1 << 0)
+
+#define HC_BUFFER_STATUS_REG 0x334
+#define ATL_BUFFER 0x1
+#define INT_BUFFER 0x2
+#define ISO_BUFFER 0x4
+#define BUFFER_MAP 0x7
+
+#define HC_MEMORY_REG 0x33c
+#define HC_PORT1_CTRL 0x374
+#define PORT1_POWER (3 << 3)
+#define PORT1_INIT1 (1 << 7)
+#define PORT1_INIT2 (1 << 23)
+
+/* Interrupt Register */
+#define HC_INTERRUPT_REG 0x310
+
+#define HC_INTERRUPT_ENABLE 0x314
+#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
+#define FINAL_HW_CONFIG (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT)
+
+#define HC_ISO_INT (1 << 9)
+#define HC_ATL_INT (1 << 8)
+#define HC_INTL_INT (1 << 7)
+#define HC_EOT_INT (1 << 3)
+#define HC_SOT_INT (1 << 1)
+
+#define HC_ISO_IRQ_MASK_OR_REG 0x318
+#define HC_INT_IRQ_MASK_OR_REG 0x31C
+#define HC_ATL_IRQ_MASK_OR_REG 0x320
+#define HC_ISO_IRQ_MASK_AND_REG 0x324
+#define HC_INT_IRQ_MASK_AND_REG 0x328
+#define HC_ATL_IRQ_MASK_AND_REG 0x32C
+
+/* Register sets */
+#define HC_BEGIN_OF_ATL 0x0c00
+#define HC_BEGIN_OF_INT 0x0800
+#define HC_BEGIN_OF_ISO 0x0400
+#define HC_BEGIN_OF_PAYLOAD 0x1000
+
+/* urb state*/
+#define DELETE_URB (0x0008)
+#define NO_TRANSFER_ACTIVE (0xffffffff)
+
+#define ATL_REGS_OFFSET (0xc00)
+#define INT_REGS_OFFSET (0x800)
+
+/* Philips Transfer Descriptor (PTD) */
+struct ptd {
+ __le32 dw0;
+ __le32 dw1;
+ __le32 dw2;
+ __le32 dw3;
+ __le32 dw4;
+ __le32 dw5;
+ __le32 dw6;
+ __le32 dw7;
+};
+
+struct inter_packet_info {
+ void *data_buffer;
+ u32 payload;
+#define PTD_FIRE_NEXT (1 << 0)
+#define PTD_URB_FINISHED (1 << 1)
+ struct urb *urb;
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+};
+
+
+typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd);
+
+#define isp1760_info(priv, fmt, args...) \
+ dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+#define isp1760_err(priv, fmt, args...) \
+ dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+/* chip memory management */
+struct memory_chunk {
+ unsigned int start;
+ unsigned int size;
+ unsigned int free;
+};
+
+/*
+ * 60kb divided in:
+ * - 32 blocks @ 256 bytes
+ * - 20 blocks @ 1024 bytes
+ * - 4 blocks @ 8192 bytes
+ */
+
+#define BLOCK_1_NUM 32
+#define BLOCK_2_NUM 20
+#define BLOCK_3_NUM 4
+
+#define BLOCK_1_SIZE 256
+#define BLOCK_2_SIZE 1024
+#define BLOCK_3_SIZE 8192
+#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
+#define PAYLOAD_SIZE 0xf000
+
+/* I saw if some reloads if the pointer was negative */
+#define ISP1760_NULL_POINTER (0x400)
+
+/* ATL */
+/* DW0 */
+#define PTD_VALID 1
+#define PTD_LENGTH(x) (((u32) x) << 3)
+#define PTD_MAXPACKET(x) (((u32) x) << 18)
+#define PTD_MULTI(x) (((u32) x) << 29)
+#define PTD_ENDPOINT(x) (((u32) x) << 31)
+/* DW1 */
+#define PTD_DEVICE_ADDR(x) (((u32) x) << 3)
+#define PTD_PID_TOKEN(x) (((u32) x) << 10)
+#define PTD_TRANS_BULK ((u32) 2 << 12)
+#define PTD_TRANS_INT ((u32) 3 << 12)
+#define PTD_TRANS_SPLIT ((u32) 1 << 14)
+#define PTD_SE_USB_LOSPEED ((u32) 2 << 16)
+#define PTD_PORT_NUM(x) (((u32) x) << 18)
+#define PTD_HUB_NUM(x) (((u32) x) << 25)
+#define PTD_PING(x) (((u32) x) << 26)
+/* DW2 */
+#define PTD_RL_CNT(x) (((u32) x) << 25)
+#define PTD_DATA_START_ADDR(x) (((u32) x) << 8)
+#define BASE_ADDR 0x1000
+/* DW3 */
+#define PTD_CERR(x) (((u32) x) << 23)
+#define PTD_NAC_CNT(x) (((u32) x) << 19)
+#define PTD_ACTIVE ((u32) 1 << 31)
+#define PTD_DATA_TOGGLE(x) (((u32) x) << 25)
+
+#define DW3_HALT_BIT (1 << 30)
+#define DW3_ERROR_BIT (1 << 28)
+#define DW3_QTD_ACTIVE (1 << 31)
+
+#define INT_UNDERRUN (1 << 2)
+#define INT_BABBLE (1 << 1)
+#define INT_EXACT (1 << 0)
+
+#define DW1_GET_PID(x) (((x) >> 10) & 0x3)
+#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff)
+#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff)
+
+#define SETUP_PID (2)
+#define IN_PID (1)
+#define OUT_PID (0)
+#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3)
+
+#define DATA_TOGGLE (1 << 31)
+#define GET_DATA_TOGGLE(x) ((x) >> 31)
+
+/* Errata 1 */
+#define RL_COUNTER (0)
+#define NAK_COUNTER (0)
+#define ERR_COUNTER (2)
+
+#define HC_ATL_PL_SIZE (8192)
+
+#endif
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
new file mode 100644
index 00000000000..73fb2a38f1e
--- /dev/null
+++ b/drivers/usb/host/isp1760-if.c
@@ -0,0 +1,298 @@
+/*
+ * Glue code for the ISP1760 driver and bus
+ * Currently there is support for
+ * - OpenFirmware
+ * - PCI
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/io.h>
+
+#include "../core/hcd.h"
+#include "isp1760-hcd.h"
+
+#ifdef CONFIG_USB_ISP1760_OF
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#endif
+
+#ifdef CONFIG_USB_ISP1760_PCI
+#include <linux/pci.h>
+#endif
+
+#ifdef CONFIG_USB_ISP1760_OF
+static int of_isp1760_probe(struct of_device *dev,
+ const struct of_device_id *match)
+{
+ struct usb_hcd *hcd;
+ struct device_node *dp = dev->node;
+ struct resource *res;
+ struct resource memory;
+ struct of_irq oirq;
+ int virq;
+ u64 res_len;
+ int ret;
+
+ ret = of_address_to_resource(dp, 0, &memory);
+ if (ret)
+ return -ENXIO;
+
+ res = request_mem_region(memory.start, memory.end - memory.start + 1,
+ dev->dev.bus_id);
+ if (!res)
+ return -EBUSY;
+
+ res_len = memory.end - memory.start + 1;
+
+ if (of_irq_map_one(dp, 0, &oirq)) {
+ ret = -ENODEV;
+ goto release_reg;
+ }
+
+ virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+
+ hcd = isp1760_register(memory.start, res_len, virq,
+ IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
+ if (IS_ERR(hcd)) {
+ ret = PTR_ERR(hcd);
+ goto release_reg;
+ }
+
+ dev_set_drvdata(&dev->dev, hcd);
+ return ret;
+
+release_reg:
+ release_mem_region(memory.start, memory.end - memory.start + 1);
+ return ret;
+}
+
+static int of_isp1760_remove(struct of_device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ return 0;
+}
+
+static struct of_device_id of_isp1760_match[] = {
+ {
+ .compatible = "nxp,usb-isp1760",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_isp1760_match);
+
+static struct of_platform_driver isp1760_of_driver = {
+ .name = "nxp-isp1760",
+ .match_table = of_isp1760_match,
+ .probe = of_isp1760_probe,
+ .remove = of_isp1760_remove,
+};
+#endif
+
+#ifdef CONFIG_USB_ISP1760_PCI
+static u32 nxp_pci_io_base;
+static u32 iolength;
+static u32 pci_mem_phy0;
+static u32 length;
+static u8 *chip_addr;
+static u8 *iobase;
+
+static int __devinit isp1761_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ u8 latency, limit;
+ __u32 reg_data;
+ int retry_count;
+ int length;
+ int status = 1;
+ struct usb_hcd *hcd;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (pci_enable_device(dev) < 0)
+ return -ENODEV;
+
+ if (!dev->irq)
+ return -ENODEV;
+
+ /* Grab the PLX PCI mem maped port start address we need */
+ nxp_pci_io_base = pci_resource_start(dev, 0);
+ iolength = pci_resource_len(dev, 0);
+
+ if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
+ printk(KERN_ERR "request region #1\n");
+ return -EBUSY;
+ }
+
+ iobase = ioremap_nocache(nxp_pci_io_base, iolength);
+ if (!iobase) {
+ printk(KERN_ERR "ioremap #1\n");
+ release_mem_region(nxp_pci_io_base, iolength);
+ return -ENOMEM;
+ }
+ /* Grab the PLX PCI shared memory of the ISP 1761 we need */
+ pci_mem_phy0 = pci_resource_start(dev, 3);
+ length = pci_resource_len(dev, 3);
+
+ if (length < 0xffff) {
+ printk(KERN_ERR "memory length for this resource is less than "
+ "required\n");
+ release_mem_region(nxp_pci_io_base, iolength);
+ iounmap(iobase);
+ return -ENOMEM;
+ }
+
+ if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) {
+ printk(KERN_ERR "host controller already in use\n");
+ release_mem_region(nxp_pci_io_base, iolength);
+ iounmap(iobase);
+ return -EBUSY;
+ }
+
+ /* bad pci latencies can contribute to overruns */
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+ if (latency) {
+ pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
+ if (limit && limit < latency)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
+ }
+
+ /* Try to check whether we can access Scratch Register of
+ * Host Controller or not. The initial PCI access is retried until
+ * local init for the PCI bridge is completed
+ */
+ retry_count = 20;
+ reg_data = 0;
+ while ((reg_data != 0xFACE) && retry_count) {
+ /*by default host is in 16bit mode, so
+ * io operations at this stage must be 16 bit
+ * */
+ writel(0xface, chip_addr + HC_SCRATCH_REG);
+ udelay(100);
+ reg_data = readl(chip_addr + HC_SCRATCH_REG);
+ retry_count--;
+ }
+
+ /* Host Controller presence is detected by writing to scratch register
+ * and reading back and checking the contents are same or not
+ */
+ if (reg_data != 0xFACE) {
+ err("scratch register mismatch %x", reg_data);
+ goto clean;
+ }
+
+ pci_set_master(dev);
+
+ status = readl(iobase + 0x68);
+ status |= 0x900;
+ writel(status, iobase + 0x68);
+
+ dev->dev.dma_mask = NULL;
+ hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
+ IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
+ pci_set_drvdata(dev, hcd);
+ if (!hcd)
+ return 0;
+clean:
+ status = -ENODEV;
+ iounmap(iobase);
+ release_mem_region(pci_mem_phy0, length);
+ release_mem_region(nxp_pci_io_base, iolength);
+ return status;
+}
+static void isp1761_pci_remove(struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+
+ hcd = pci_get_drvdata(dev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ pci_disable_device(dev);
+
+ iounmap(iobase);
+ iounmap(chip_addr);
+
+ release_mem_region(nxp_pci_io_base, iolength);
+ release_mem_region(pci_mem_phy0, length);
+}
+
+static void isp1761_pci_shutdown(struct pci_dev *dev)
+{
+ printk(KERN_ERR "ips1761_pci_shutdown\n");
+}
+
+static const struct pci_device_id isp1760_plx [] = { {
+ /* handle any USB 2.0 EHCI controller */
+ PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0),
+ .driver_data = 0,
+},
+{ /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, isp1760_plx);
+
+static struct pci_driver isp1761_pci_driver = {
+ .name = "isp1760",
+ .id_table = isp1760_plx,
+ .probe = isp1761_pci_probe,
+ .remove = isp1761_pci_remove,
+ .shutdown = isp1761_pci_shutdown,
+};
+#endif
+
+static int __init isp1760_init(void)
+{
+ int ret;
+
+ init_kmem_once();
+
+#ifdef CONFIG_USB_ISP1760_OF
+ ret = of_register_platform_driver(&isp1760_of_driver);
+ if (ret) {
+ deinit_kmem_cache();
+ return ret;
+ }
+#endif
+#ifdef CONFIG_USB_ISP1760_PCI
+ ret = pci_register_driver(&isp1761_pci_driver);
+ if (ret)
+ goto unreg_of;
+#endif
+ return ret;
+
+#ifdef CONFIG_USB_ISP1760_PCI
+unreg_of:
+#endif
+#ifdef CONFIG_USB_ISP1760_OF
+ of_unregister_platform_driver(&isp1760_of_driver);
+#endif
+ deinit_kmem_cache();
+ return ret;
+}
+module_init(isp1760_init);
+
+static void __exit isp1760_exit(void)
+{
+#ifdef CONFIG_USB_ISP1760_OF
+ of_unregister_platform_driver(&isp1760_of_driver);
+#endif
+#ifdef CONFIG_USB_ISP1760_PCI
+ pci_unregister_driver(&isp1761_pci_driver);
+#endif
+ deinit_kmem_cache();
+}
+module_exit(isp1760_exit);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 17dc2eccda8..79a78029f89 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -613,7 +613,7 @@ static void start_hnp(struct ohci_hcd *ohci);
static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
{
__hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
- u32 temp;
+ u32 temp = 0;
u16 now = ohci_readl(ohci, &ohci->regs->fmnumber);
u16 reset_done = now + PORT_RESET_MSEC;
int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC);
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index d3e0d8aa398..3a7bfe7a887 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -234,7 +234,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
return 0;
}
-static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
+static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
{
int port;
const char *sys_info;
@@ -261,27 +261,60 @@ __releases(uhci->lock)
__acquires(uhci->lock)
{
int auto_stop;
- int int_enable, egsm_enable;
+ int int_enable, egsm_enable, wakeup_enable;
struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
dev_dbg(&rhdev->dev, "%s%s\n", __func__,
(auto_stop ? " (auto-stop)" : ""));
- /* Enable resume-detect interrupts if they work.
- * Then enter Global Suspend mode if _it_ works, still configured.
+ /* Start off by assuming Resume-Detect interrupts and EGSM work
+ * and that remote wakeups should be enabled.
*/
egsm_enable = USBCMD_EGSM;
- uhci->working_RD = 1;
+ uhci->RD_enable = 1;
int_enable = USBINTR_RESUME;
- if (remote_wakeup_is_broken(uhci))
- egsm_enable = 0;
- if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
+ wakeup_enable = 1;
+
+ /* In auto-stop mode wakeups must always be detected, but
+ * Resume-Detect interrupts may be prohibited. (In the absence
+ * of CONFIG_PM, they are always disallowed.)
+ */
+ if (auto_stop) {
+ if (!device_may_wakeup(&rhdev->dev))
+ int_enable = 0;
+
+ /* In bus-suspend mode wakeups may be disabled, but if they are
+ * allowed then so are Resume-Detect interrupts.
+ */
+ } else {
#ifdef CONFIG_PM
- (!auto_stop && !rhdev->do_remote_wakeup) ||
+ if (!rhdev->do_remote_wakeup)
+ wakeup_enable = 0;
#endif
- (auto_stop && !device_may_wakeup(&rhdev->dev)))
- uhci->working_RD = int_enable = 0;
+ }
+
+ /* EGSM causes the root hub to echo a 'K' signal (resume) out any
+ * port which requests a remote wakeup. According to the USB spec,
+ * every hub is supposed to do this. But if we are ignoring
+ * remote-wakeup requests anyway then there's no point to it.
+ * We also shouldn't enable EGSM if it's broken.
+ */
+ if (!wakeup_enable || global_suspend_mode_is_broken(uhci))
+ egsm_enable = 0;
+
+ /* If we're ignoring wakeup events then there's no reason to
+ * enable Resume-Detect interrupts. We also shouldn't enable
+ * them if they are broken or disallowed.
+ *
+ * This logic may lead us to enabling RD but not EGSM. The UHCI
+ * spec foolishly says that RD works only when EGSM is on, but
+ * there's no harm in enabling it anyway -- perhaps some chips
+ * will implement it!
+ */
+ if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) ||
+ !int_enable)
+ uhci->RD_enable = int_enable = 0;
outw(int_enable, uhci->io_addr + USBINTR);
outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
@@ -308,7 +341,11 @@ __acquires(uhci->lock)
uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED;
- uhci_to_hcd(uhci)->poll_rh = !int_enable;
+
+ /* If interrupts don't work and remote wakeup is enabled then
+ * the suspended root hub needs to be polled.
+ */
+ uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable);
uhci_scan_schedule(uhci);
uhci_fsbr_off(uhci);
@@ -344,9 +381,12 @@ __acquires(uhci->lock)
* for 20 ms.
*/
if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+ unsigned egsm;
+
+ /* Keep EGSM on if it was set before */
+ egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM;
uhci->rh_state = UHCI_RH_RESUMING;
- outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
- uhci->io_addr + USBCMD);
+ outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD);
spin_unlock_irq(&uhci->lock);
msleep(20);
spin_lock_irq(&uhci->lock);
@@ -801,8 +841,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
spin_unlock_irq(&uhci->lock);
- if (!uhci->working_RD) {
- /* Suspended root hub needs to be polled */
+ /* If interrupts don't work and remote wakeup is enabled then
+ * the suspended root hub needs to be polled.
+ */
+ if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) {
hcd->poll_rh = 1;
usb_hcd_poll_rh_status(hcd);
}
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 340d6ed3e6e..7d01c5677f9 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -400,8 +400,9 @@ struct uhci_hcd {
unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */
unsigned int dead:1; /* Controller has died */
- unsigned int working_RD:1; /* Suspended root hub doesn't
- need to be polled */
+ unsigned int RD_enable:1; /* Suspended root hub with
+ Resume-Detect interrupts
+ enabled */
unsigned int is_initialized:1; /* Data structure is usable */
unsigned int fsbr_is_on:1; /* FSBR is turned on */
unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 11580e81e2c..7aafd53fbca 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -148,7 +148,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
/* Structure to hold all of our device specific stuff */
struct ld_usb {
- struct semaphore sem; /* locks this structure */
+ struct mutex mutex; /* locks this structure */
struct usb_interface* intf; /* save off the usb interface pointer */
int open_count; /* number of times this port has been opened */
@@ -319,7 +319,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
return -ENODEV;
/* lock this device */
- if (down_interruptible(&dev->sem))
+ if (mutex_lock_interruptible(&dev->mutex))
return -ERESTARTSYS;
/* allow opening only once */
@@ -358,7 +358,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
file->private_data = dev;
unlock_exit:
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
return retval;
}
@@ -378,7 +378,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
goto exit;
}
- if (down_interruptible(&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -389,7 +389,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
}
if (dev->intf == NULL) {
/* the device was unplugged before the file was released */
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
/* unlock here as ld_usb_delete frees dev */
ld_usb_delete(dev);
goto exit;
@@ -402,7 +402,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
dev->open_count = 0;
unlock_exit:
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
exit:
return retval;
@@ -448,7 +448,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
goto exit;
/* lock this object */
- if (down_interruptible(&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -505,7 +505,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
unlock_exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
exit:
return retval;
@@ -528,7 +528,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
goto exit;
/* lock this object */
- if (down_interruptible(&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -602,7 +602,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
unlock_exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
exit:
return retval;
@@ -651,7 +651,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
dev_err(&intf->dev, "Out of memory\n");
goto exit;
}
- init_MUTEX(&dev->sem);
+ mutex_init(&dev->mutex);
spin_lock_init(&dev->rbsl);
dev->intf = intf;
init_waitqueue_head(&dev->read_wait);
@@ -765,15 +765,15 @@ static void ld_usb_disconnect(struct usb_interface *intf)
/* give back our minor */
usb_deregister_dev(intf, &ld_usb_class);
- down(&dev->sem);
+ mutex_lock(&dev->mutex);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
ld_usb_delete(dev);
} else {
dev->intf = NULL;
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
}
dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index a51983854ca..742be3c3594 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -79,30 +79,10 @@ static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test)
/* set up all urbs so they can be used with either bulk or interrupt */
#define INTERRUPT_RATE 1 /* msec/transfer */
-#define xprintk(tdev,level,fmt,args...) \
- dev_printk(level , &(tdev)->intf->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG DBG
-#else
-#define VDBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
- xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
+#define ERROR(tdev, fmt, args...) \
+ dev_err(&(tdev)->intf->dev , fmt , ## args)
+#define WARN(tdev, fmt, args...) \
+ dev_warn(&(tdev)->intf->dev , fmt , ## args)
/*-------------------------------------------------------------------------*/
@@ -236,7 +216,7 @@ static struct urb *simple_alloc_urb (
static unsigned pattern = 0;
module_param (pattern, uint, S_IRUGO);
-// MODULE_PARM_DESC (pattern, "i/o pattern (0 == zeroes)");
+MODULE_PARM_DESC(pattern, "i/o pattern (0 == zeroes)");
static inline void simple_fill_buf (struct urb *urb)
{
@@ -257,7 +237,7 @@ static inline void simple_fill_buf (struct urb *urb)
}
}
-static inline int simple_check_buf (struct urb *urb)
+static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
{
unsigned i;
u8 expected;
@@ -285,7 +265,7 @@ static inline int simple_check_buf (struct urb *urb)
}
if (*buf == expected)
continue;
- dbg ("buf[%d] = %d (not %d)", i, *buf, expected);
+ ERROR(tdev, "buf[%d] = %d (not %d)\n", i, *buf, expected);
return -EINVAL;
}
return 0;
@@ -299,6 +279,7 @@ static void simple_free_urb (struct urb *urb)
}
static int simple_io (
+ struct usbtest_dev *tdev,
struct urb *urb,
int iterations,
int vary,
@@ -324,7 +305,7 @@ static int simple_io (
retval = urb->status;
urb->dev = udev;
if (retval == 0 && usb_pipein (urb->pipe))
- retval = simple_check_buf (urb);
+ retval = simple_check_buf(tdev, urb);
if (vary) {
int len = urb->transfer_buffer_length;
@@ -341,7 +322,7 @@ static int simple_io (
urb->transfer_buffer_length = max;
if (expected != retval)
- dev_dbg (&udev->dev,
+ dev_err(&udev->dev,
"%s failed, iterations left %d, status %d (not %d)\n",
label, iterations, retval, expected);
return retval;
@@ -357,7 +338,7 @@ static int simple_io (
static void free_sglist (struct scatterlist *sg, int nents)
{
unsigned i;
-
+
if (!sg)
return;
for (i = 0; i < nents; i++) {
@@ -415,7 +396,7 @@ alloc_sglist (int nents, int max, int vary)
}
static int perform_sglist (
- struct usb_device *udev,
+ struct usbtest_dev *tdev,
unsigned iterations,
int pipe,
struct usb_sg_request *req,
@@ -423,6 +404,7 @@ static int perform_sglist (
int nents
)
{
+ struct usb_device *udev = testdev_to_usbdev(tdev);
int retval = 0;
while (retval == 0 && iterations-- > 0) {
@@ -431,7 +413,7 @@ static int perform_sglist (
? (INTERRUPT_RATE << 3)
: INTERRUPT_RATE,
sg, nents, 0, GFP_KERNEL);
-
+
if (retval)
break;
usb_sg_wait (req);
@@ -446,7 +428,8 @@ static int perform_sglist (
// failure if retval is as we expected ...
if (retval)
- dbg ("perform_sglist failed, iterations left %d, status %d",
+ ERROR(tdev, "perform_sglist failed, "
+ "iterations left %d, status %d\n",
iterations, retval);
return retval;
}
@@ -505,28 +488,28 @@ static int set_altsetting (struct usbtest_dev *dev, int alternate)
alternate);
}
-static int is_good_config (char *buf, int len)
+static int is_good_config(struct usbtest_dev *tdev, int len)
{
struct usb_config_descriptor *config;
-
+
if (len < sizeof *config)
return 0;
- config = (struct usb_config_descriptor *) buf;
+ config = (struct usb_config_descriptor *) tdev->buf;
switch (config->bDescriptorType) {
case USB_DT_CONFIG:
case USB_DT_OTHER_SPEED_CONFIG:
if (config->bLength != 9) {
- dbg ("bogus config descriptor length");
+ ERROR(tdev, "bogus config descriptor length\n");
return 0;
}
/* this bit 'must be 1' but often isn't */
if (!realworld && !(config->bmAttributes & 0x80)) {
- dbg ("high bit of config attributes not set");
+ ERROR(tdev, "high bit of config attributes not set\n");
return 0;
}
if (config->bmAttributes & 0x1f) { /* reserved == 0 */
- dbg ("reserved config bits set");
+ ERROR(tdev, "reserved config bits set\n");
return 0;
}
break;
@@ -538,7 +521,7 @@ static int is_good_config (char *buf, int len)
return 1;
if (le16_to_cpu(config->wTotalLength) >= TBUF_SIZE) /* max partial read */
return 1;
- dbg ("bogus config descriptor read size");
+ ERROR(tdev, "bogus config descriptor read size\n");
return 0;
}
@@ -571,7 +554,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* 9.2.3 constrains the range here */
alt = iface->altsetting [i].desc.bAlternateSetting;
if (alt < 0 || alt >= iface->num_altsetting) {
- dev_dbg (&iface->dev,
+ dev_err(&iface->dev,
"invalid alt [%d].bAltSetting = %d\n",
i, alt);
}
@@ -583,7 +566,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* [9.4.10] set_interface */
retval = set_altsetting (dev, alt);
if (retval) {
- dev_dbg (&iface->dev, "can't set_interface = %d, %d\n",
+ dev_err(&iface->dev, "can't set_interface = %d, %d\n",
alt, retval);
return retval;
}
@@ -591,7 +574,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* [9.4.4] get_interface always works */
retval = get_altsetting (dev);
if (retval != alt) {
- dev_dbg (&iface->dev, "get alt should be %d, was %d\n",
+ dev_err(&iface->dev, "get alt should be %d, was %d\n",
alt, retval);
return (retval < 0) ? retval : -EDOM;
}
@@ -611,7 +594,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
USB_DIR_IN | USB_RECIP_DEVICE,
0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
if (retval != 1 || dev->buf [0] != expected) {
- dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
+ dev_err(&iface->dev, "get config --> %d %d (1 %d)\n",
retval, dev->buf[0], expected);
return (retval < 0) ? retval : -EDOM;
}
@@ -621,7 +604,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_get_descriptor (udev, USB_DT_DEVICE, 0,
dev->buf, sizeof udev->descriptor);
if (retval != sizeof udev->descriptor) {
- dev_dbg (&iface->dev, "dev descriptor --> %d\n", retval);
+ dev_err(&iface->dev, "dev descriptor --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
}
@@ -629,8 +612,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
retval = usb_get_descriptor (udev, USB_DT_CONFIG, i,
dev->buf, TBUF_SIZE);
- if (!is_good_config (dev->buf, retval)) {
- dev_dbg (&iface->dev,
+ if (!is_good_config(dev, retval)) {
+ dev_err(&iface->dev,
"config [%d] descriptor --> %d\n",
i, retval);
return (retval < 0) ? retval : -EDOM;
@@ -650,14 +633,14 @@ static int ch9_postconfig (struct usbtest_dev *dev)
sizeof (struct usb_qualifier_descriptor));
if (retval == -EPIPE) {
if (udev->speed == USB_SPEED_HIGH) {
- dev_dbg (&iface->dev,
+ dev_err(&iface->dev,
"hs dev qualifier --> %d\n",
retval);
return (retval < 0) ? retval : -EDOM;
}
/* usb2.0 but not high-speed capable; fine */
} else if (retval != sizeof (struct usb_qualifier_descriptor)) {
- dev_dbg (&iface->dev, "dev qualifier --> %d\n", retval);
+ dev_err(&iface->dev, "dev qualifier --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
} else
d = (struct usb_qualifier_descriptor *) dev->buf;
@@ -669,8 +652,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_get_descriptor (udev,
USB_DT_OTHER_SPEED_CONFIG, i,
dev->buf, TBUF_SIZE);
- if (!is_good_config (dev->buf, retval)) {
- dev_dbg (&iface->dev,
+ if (!is_good_config(dev, retval)) {
+ dev_err(&iface->dev,
"other speed config --> %d\n",
retval);
return (retval < 0) ? retval : -EDOM;
@@ -683,7 +666,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* [9.4.5] get_status always works */
retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf);
if (retval != 2) {
- dev_dbg (&iface->dev, "get dev status --> %d\n", retval);
+ dev_err(&iface->dev, "get dev status --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
}
@@ -693,11 +676,11 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_get_status (udev, USB_RECIP_INTERFACE,
iface->altsetting [0].desc.bInterfaceNumber, dev->buf);
if (retval != 2) {
- dev_dbg (&iface->dev, "get interface status --> %d\n", retval);
+ dev_err(&iface->dev, "get interface status --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
}
// FIXME get status for each endpoint in the interface
-
+
return 0;
}
@@ -752,8 +735,9 @@ static void ctrl_complete (struct urb *urb)
*/
if (subcase->number > 0) {
if ((subcase->number - ctx->last) != 1) {
- dbg ("subcase %d completed out of order, last %d",
- subcase->number, ctx->last);
+ ERROR(ctx->dev,
+ "subcase %d completed out of order, last %d\n",
+ subcase->number, ctx->last);
status = -EDOM;
ctx->last = subcase->number;
goto error;
@@ -777,7 +761,7 @@ static void ctrl_complete (struct urb *urb)
else if (subcase->number == 12 && status == -EPIPE)
status = 0;
else
- dbg ("subtest %d error, status %d",
+ ERROR(ctx->dev, "subtest %d error, status %d\n",
subcase->number, status);
}
@@ -788,9 +772,12 @@ error:
int i;
ctx->status = status;
- info ("control queue %02x.%02x, err %d, %d left",
+ ERROR(ctx->dev, "control queue %02x.%02x, err %d, "
+ "%d left, subcase %d, len %d/%d\n",
reqp->bRequestType, reqp->bRequest,
- status, ctx->count);
+ status, ctx->count, subcase->number,
+ urb->actual_length,
+ urb->transfer_buffer_length);
/* FIXME this "unlink everything" exit route should
* be a separate test case.
@@ -799,7 +786,8 @@ error:
/* unlink whatever's still pending */
for (i = 1; i < ctx->param->sglen; i++) {
struct urb *u = ctx->urb [
- (i + subcase->number) % ctx->param->sglen];
+ (i + subcase->number)
+ % ctx->param->sglen];
if (u == urb || !u->dev)
continue;
@@ -812,7 +800,8 @@ error:
case -EIDRM:
continue;
default:
- dbg ("urb unlink --> %d", status);
+ ERROR(ctx->dev, "urb unlink --> %d\n",
+ status);
}
}
status = ctx->status;
@@ -822,14 +811,15 @@ error:
/* resubmit if we need to, else mark this as done */
if ((status == 0) && (ctx->pending < ctx->count)) {
if ((status = usb_submit_urb (urb, GFP_ATOMIC)) != 0) {
- dbg ("can't resubmit ctrl %02x.%02x, err %d",
+ ERROR(ctx->dev,
+ "can't resubmit ctrl %02x.%02x, err %d\n",
reqp->bRequestType, reqp->bRequest, status);
urb->dev = NULL;
} else
ctx->pending++;
} else
urb->dev = NULL;
-
+
/* signal completion when nothing's queued */
if (ctx->pending == 0)
complete (&ctx->complete);
@@ -918,11 +908,11 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8);
// interface == 0
len = sizeof (struct usb_interface_descriptor);
- expected = EPIPE;
+ expected = -EPIPE;
break;
// NOTE: two consecutive stalls in the queue here.
// that tests fault recovery a bit more aggressively.
- case 8: // clear endpoint halt (USUALLY STALLS)
+ case 8: // clear endpoint halt (MAY STALL)
req.bRequest = USB_REQ_CLEAR_FEATURE;
req.bRequestType = USB_RECIP_ENDPOINT;
// wValue 0 == ep halt
@@ -965,7 +955,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
break;
case 14: // short read; try to fill the last packet
req.wValue = cpu_to_le16 ((USB_DT_DEVICE << 8) | 0);
- // device descriptor size == 18 bytes
+ /* device descriptor size == 18 bytes */
len = udev->descriptor.bMaxPacketSize0;
switch (len) {
case 8: len = 24; break;
@@ -974,7 +964,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
expected = -EREMOTEIO;
break;
default:
- err ("bogus number of ctrl queue testcases!");
+ ERROR(dev, "bogus number of ctrl queue testcases!\n");
context.status = -EINVAL;
goto cleanup;
}
@@ -1003,7 +993,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
for (i = 0; i < param->sglen; i++) {
context.status = usb_submit_urb (urb [i], GFP_ATOMIC);
if (context.status != 0) {
- dbg ("can't submit urb[%d], status %d",
+ ERROR(dev, "can't submit urb[%d], status %d\n",
i, context.status);
context.count = context.pending;
break;
@@ -1070,7 +1060,7 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
* due to errors, or is just NAKing requests.
*/
if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) {
- dev_dbg (&dev->intf->dev, "submit fail %d\n", retval);
+ dev_err(&dev->intf->dev, "submit fail %d\n", retval);
return retval;
}
@@ -1087,13 +1077,13 @@ retry:
* "normal" drivers would prevent resubmission, but
* since we're testing unlink paths, we can't.
*/
- dev_dbg (&dev->intf->dev, "unlink retry\n");
+ ERROR(dev, "unlink retry\n");
goto retry;
}
} else
usb_kill_urb (urb);
if (!(retval == 0 || retval == -EINPROGRESS)) {
- dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval);
+ dev_err(&dev->intf->dev, "unlink fail %d\n", retval);
return retval;
}
@@ -1121,7 +1111,7 @@ static int unlink_simple (struct usbtest_dev *dev, int pipe, int len)
/*-------------------------------------------------------------------------*/
-static int verify_not_halted (int ep, struct urb *urb)
+static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
u16 status;
@@ -1129,20 +1119,21 @@ static int verify_not_halted (int ep, struct urb *urb)
/* shouldn't look or act halted */
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
if (retval < 0) {
- dbg ("ep %02x couldn't get no-halt status, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't get no-halt status, %d\n",
+ ep, retval);
return retval;
}
if (status != 0) {
- dbg ("ep %02x bogus status: %04x != 0", ep, status);
+ ERROR(tdev, "ep %02x bogus status: %04x != 0\n", ep, status);
return -EINVAL;
}
- retval = simple_io (urb, 1, 0, 0, __func__);
+ retval = simple_io(tdev, urb, 1, 0, 0, __func__);
if (retval != 0)
return -EINVAL;
return 0;
}
-static int verify_halted (int ep, struct urb *urb)
+static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
u16 status;
@@ -1150,29 +1141,30 @@ static int verify_halted (int ep, struct urb *urb)
/* should look and act halted */
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
if (retval < 0) {
- dbg ("ep %02x couldn't get halt status, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't get halt status, %d\n",
+ ep, retval);
return retval;
}
le16_to_cpus(&status);
if (status != 1) {
- dbg ("ep %02x bogus status: %04x != 1", ep, status);
+ ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);
return -EINVAL;
}
- retval = simple_io (urb, 1, 0, -EPIPE, __func__);
+ retval = simple_io(tdev, urb, 1, 0, -EPIPE, __func__);
if (retval != -EPIPE)
return -EINVAL;
- retval = simple_io (urb, 1, 0, -EPIPE, "verify_still_halted");
+ retval = simple_io(tdev, urb, 1, 0, -EPIPE, "verify_still_halted");
if (retval != -EPIPE)
return -EINVAL;
return 0;
}
-static int test_halt (int ep, struct urb *urb)
+static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
/* shouldn't look or act halted now */
- retval = verify_not_halted (ep, urb);
+ retval = verify_not_halted(tdev, ep, urb);
if (retval < 0)
return retval;
@@ -1182,20 +1174,20 @@ static int test_halt (int ep, struct urb *urb)
USB_ENDPOINT_HALT, ep,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval < 0) {
- dbg ("ep %02x couldn't set halt, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't set halt, %d\n", ep, retval);
return retval;
}
- retval = verify_halted (ep, urb);
+ retval = verify_halted(tdev, ep, urb);
if (retval < 0)
return retval;
/* clear halt (tests API + protocol), verify it worked */
retval = usb_clear_halt (urb->dev, urb->pipe);
if (retval < 0) {
- dbg ("ep %02x couldn't clear halt, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
return retval;
}
- retval = verify_not_halted (ep, urb);
+ retval = verify_not_halted(tdev, ep, urb);
if (retval < 0)
return retval;
@@ -1217,7 +1209,7 @@ static int halt_simple (struct usbtest_dev *dev)
if (dev->in_pipe) {
ep = usb_pipeendpoint (dev->in_pipe) | USB_DIR_IN;
urb->pipe = dev->in_pipe;
- retval = test_halt (ep, urb);
+ retval = test_halt(dev, ep, urb);
if (retval < 0)
goto done;
}
@@ -1225,7 +1217,7 @@ static int halt_simple (struct usbtest_dev *dev)
if (dev->out_pipe) {
ep = usb_pipeendpoint (dev->out_pipe);
urb->pipe = dev->out_pipe;
- retval = test_halt (ep, urb);
+ retval = test_halt(dev, ep, urb);
}
done:
simple_free_urb (urb);
@@ -1275,7 +1267,7 @@ static int ctrl_out (struct usbtest_dev *dev,
if (retval != len) {
what = "write";
if (retval >= 0) {
- INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
+ ERROR(dev, "ctrl_out, wlen %d (expected %d)\n",
retval, len);
retval = -EBADMSG;
}
@@ -1289,7 +1281,7 @@ static int ctrl_out (struct usbtest_dev *dev,
if (retval != len) {
what = "read";
if (retval >= 0) {
- INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
+ ERROR(dev, "ctrl_out, rlen %d (expected %d)\n",
retval, len);
retval = -EBADMSG;
}
@@ -1299,7 +1291,7 @@ static int ctrl_out (struct usbtest_dev *dev,
/* fail if we can't verify */
for (j = 0; j < len; j++) {
if (buf [j] != (u8) (i + j)) {
- INFO (dev, "ctrl_out, byte %d is %d not %d\n",
+ ERROR(dev, "ctrl_out, byte %d is %d not %d\n",
j, buf [j], (u8) i + j);
retval = -EBADMSG;
break;
@@ -1321,7 +1313,7 @@ static int ctrl_out (struct usbtest_dev *dev,
}
if (retval < 0)
- INFO (dev, "ctrl_out %s failed, code %d, count %d\n",
+ ERROR (dev, "ctrl_out %s failed, code %d, count %d\n",
what, retval, i);
kfree (buf);
@@ -1366,7 +1358,7 @@ static void iso_callback (struct urb *urb)
case 0:
goto done;
default:
- dev_dbg (&ctx->dev->intf->dev,
+ dev_err(&ctx->dev->intf->dev,
"iso resubmit err %d\n",
status);
/* FALLTHROUGH */
@@ -1381,7 +1373,7 @@ static void iso_callback (struct urb *urb)
ctx->pending--;
if (ctx->pending == 0) {
if (ctx->errors)
- dev_dbg (&ctx->dev->intf->dev,
+ dev_err(&ctx->dev->intf->dev,
"iso test, %lu errors out of %lu\n",
ctx->errors, ctx->packet_count);
complete (&ctx->done);
@@ -1458,7 +1450,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
memset (urbs, 0, sizeof urbs);
udev = testdev_to_usbdev (dev);
- dev_dbg (&dev->intf->dev,
+ dev_info(&dev->intf->dev,
"... iso period %d %sframes, wMaxPacket %04x\n",
1 << (desc->bInterval - 1),
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
@@ -1475,7 +1467,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
urbs [i]->context = &context;
}
packets *= param->iterations;
- dev_dbg (&dev->intf->dev,
+ dev_info(&dev->intf->dev,
"... total %lu msec (%lu packets)\n",
(packets * (1 << (desc->bInterval - 1)))
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
@@ -1537,6 +1529,13 @@ fail:
* except indirectly by consuming USB bandwidth and CPU resources for test
* threads and request completion. But the only way to know that for sure
* is to test when HC queues are in use by many devices.
+ *
+ * WARNING: Because usbfs grabs udev->dev.sem before calling this ioctl(),
+ * it locks out usbcore in certain code paths. Notably, if you disconnect
+ * the device-under-test, khubd will wait block forever waiting for the
+ * ioctl to complete ... so that usb_disconnect() can abort the pending
+ * urbs and then call usbtest_disconnect(). To abort a test, you're best
+ * off just killing the userspace task and waiting for it to exit.
*/
static int
@@ -1575,7 +1574,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
* altsettings; force a default so most tests don't need to check.
*/
if (dev->info->alt >= 0) {
- int res;
+ int res;
if (intf->altsetting->desc.bInterfaceNumber) {
mutex_unlock(&dev->lock);
@@ -1604,7 +1603,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
switch (param->test_num) {
case 0:
- dev_dbg (&intf->dev, "TEST 0: NOP\n");
+ dev_info(&intf->dev, "TEST 0: NOP\n");
retval = 0;
break;
@@ -1612,7 +1611,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 1:
if (dev->out_pipe == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 1: write %d bytes %u times\n",
param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
@@ -1621,13 +1620,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = simple_io (urb, param->iterations, 0, 0, "test1");
+ retval = simple_io(dev, urb, param->iterations, 0, 0, "test1");
simple_free_urb (urb);
break;
case 2:
if (dev->in_pipe == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 2: read %d bytes %u times\n",
param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
@@ -1636,13 +1635,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = simple_io (urb, param->iterations, 0, 0, "test2");
+ retval = simple_io(dev, urb, param->iterations, 0, 0, "test2");
simple_free_urb (urb);
break;
case 3:
if (dev->out_pipe == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 3: write/%d 0..%d bytes %u times\n",
param->vary, param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
@@ -1651,14 +1650,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = simple_io (urb, param->iterations, param->vary,
+ retval = simple_io(dev, urb, param->iterations, param->vary,
0, "test3");
simple_free_urb (urb);
break;
case 4:
if (dev->in_pipe == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 4: read/%d 0..%d bytes %u times\n",
param->vary, param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
@@ -1667,7 +1666,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = simple_io (urb, param->iterations, param->vary,
+ retval = simple_io(dev, urb, param->iterations, param->vary,
0, "test4");
simple_free_urb (urb);
break;
@@ -1676,7 +1675,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 5:
if (dev->out_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 5: write %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1686,7 +1685,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = perform_sglist (udev, param->iterations, dev->out_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->out_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
@@ -1694,7 +1693,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 6:
if (dev->in_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 6: read %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1704,14 +1703,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = perform_sglist (udev, param->iterations, dev->in_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->in_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
case 7:
if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 7: write/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length);
@@ -1721,14 +1720,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = perform_sglist (udev, param->iterations, dev->out_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->out_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
case 8:
if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 8: read/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length);
@@ -1738,7 +1737,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = perform_sglist (udev, param->iterations, dev->in_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->in_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
@@ -1746,13 +1745,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
/* non-queued sanity tests for control (chapter 9 subset) */
case 9:
retval = 0;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 9: ch9 (subset) control tests, %d times\n",
param->iterations);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = ch9_postconfig (dev);
if (retval)
- dbg ("ch9 subset failed, iterations left %d", i);
+ dev_err(&intf->dev, "ch9 subset failed, "
+ "iterations left %d\n", i);
break;
/* queued control messaging */
@@ -1760,7 +1760,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (param->sglen == 0)
break;
retval = 0;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 10: queue %d control calls, %d times\n",
param->sglen,
param->iterations);
@@ -1772,26 +1772,26 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (dev->in_pipe == 0 || !param->length)
break;
retval = 0;
- dev_dbg (&intf->dev, "TEST 11: unlink %d reads of %d\n",
+ dev_info(&intf->dev, "TEST 11: unlink %d reads of %d\n",
param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->in_pipe,
param->length);
if (retval)
- dev_dbg (&intf->dev, "unlink reads failed %d, "
+ dev_err(&intf->dev, "unlink reads failed %d, "
"iterations left %d\n", retval, i);
break;
case 12:
if (dev->out_pipe == 0 || !param->length)
break;
retval = 0;
- dev_dbg (&intf->dev, "TEST 12: unlink %d writes of %d\n",
+ dev_info(&intf->dev, "TEST 12: unlink %d writes of %d\n",
param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->out_pipe,
param->length);
if (retval)
- dev_dbg (&intf->dev, "unlink writes failed %d, "
+ dev_err(&intf->dev, "unlink writes failed %d, "
"iterations left %d\n", retval, i);
break;
@@ -1800,24 +1800,24 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (dev->out_pipe == 0 && dev->in_pipe == 0)
break;
retval = 0;
- dev_dbg (&intf->dev, "TEST 13: set/clear %d halts\n",
+ dev_info(&intf->dev, "TEST 13: set/clear %d halts\n",
param->iterations);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = halt_simple (dev);
-
+
if (retval)
- DBG (dev, "halts failed, iterations left %d\n", i);
+ ERROR(dev, "halts failed, iterations left %d\n", i);
break;
/* control write tests */
case 14:
if (!dev->info->ctrl_out)
break;
- dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
+ dev_info(&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
param->iterations,
realworld ? 1 : 0, param->length,
param->vary);
- retval = ctrl_out (dev, param->iterations,
+ retval = ctrl_out(dev, param->iterations,
param->length, param->vary);
break;
@@ -1825,7 +1825,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 15:
if (dev->out_iso_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 15: write %d iso, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1838,7 +1838,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 16:
if (dev->in_iso_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 16: read %d iso, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1898,7 +1898,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
return -ENODEV;
if (product && le16_to_cpu(udev->descriptor.idProduct) != (u16)product)
return -ENODEV;
- dbg ("matched module params, vend=0x%04x prod=0x%04x",
+ dev_info(&intf->dev, "matched module params, "
+ "vend=0x%04x prod=0x%04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
}
@@ -1940,7 +1941,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
status = get_endpoints (dev, intf);
if (status < 0) {
- dbg ("couldn't get endpoints, %d\n", status);
+ WARN(dev, "couldn't get endpoints, %d\n",
+ status);
return status;
}
/* may find bulk or ISO pipes */
@@ -2082,21 +2084,9 @@ static struct usbtest_info generic_info = {
};
#endif
-// FIXME remove this
-static struct usbtest_info hact_info = {
- .name = "FX2/hact",
- //.ep_in = 6,
- .ep_out = 2,
- .alt = -1,
-};
-
static struct usb_device_id id_table [] = {
- { USB_DEVICE (0x0547, 0x1002),
- .driver_info = (unsigned long) &hact_info,
- },
-
/*-------------------------------------------------------------*/
/* EZ-USB devices which download firmware to replace (or in our
@@ -2185,7 +2175,7 @@ static int __init usbtest_init (void)
{
#ifdef GENERIC
if (vendor)
- dbg ("params: vend=0x%04x prod=0x%04x", vendor, product);
+ pr_debug("params: vend=0x%04x prod=0x%04x\n", vendor, product);
#endif
return usb_register (&usbtest_driver);
}
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 9b1bb347dc2..db6f97a93c0 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -147,7 +147,7 @@ static void serial_buf_free(struct circ_buf *cb)
*/
static int serial_buf_data_avail(struct circ_buf *cb)
{
- return CIRC_CNT(cb->head,cb->tail,AIRCABLE_BUF_SIZE);
+ return CIRC_CNT(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
}
/*
@@ -171,7 +171,7 @@ static int serial_buf_put(struct circ_buf *cb, const char *buf, int count)
cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1);
buf += c;
count -= c;
- ret= c;
+ ret = c;
}
return ret;
}
@@ -197,7 +197,7 @@ static int serial_buf_get(struct circ_buf *cb, char *buf, int count)
cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
buf += c;
count -= c;
- ret= c;
+ ret = c;
}
return ret;
}
@@ -208,7 +208,7 @@ static void aircable_send(struct usb_serial_port *port)
{
int count, result;
struct aircable_private *priv = usb_get_serial_port_data(port);
- unsigned char* buf;
+ unsigned char *buf;
__le16 *dbuf;
dbg("%s - port %d", __func__, port->number);
if (port->write_urb_busy)
@@ -229,7 +229,8 @@ static void aircable_send(struct usb_serial_port *port)
buf[1] = TX_HEADER_1;
dbuf = (__le16 *)&buf[2];
*dbuf = cpu_to_le16((u16)count);
- serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
+ serial_buf_get(priv->tx_buf, buf + HCI_HEADER_LENGTH,
+ MAX_HCI_FRAMESIZE);
memcpy(port->write_urb->transfer_buffer, buf,
count + HCI_HEADER_LENGTH);
@@ -261,7 +262,7 @@ static void aircable_read(struct work_struct *work)
struct tty_struct *tty;
unsigned char *data;
int count;
- if (priv->rx_flags & THROTTLED){
+ if (priv->rx_flags & THROTTLED) {
if (priv->rx_flags & ACTUALLY_THROTTLED)
schedule_work(&priv->rx_work);
return;
@@ -282,10 +283,10 @@ static void aircable_read(struct work_struct *work)
count = min(64, serial_buf_data_avail(priv->rx_buf));
if (count <= 0)
- return; //We have finished sending everything.
+ return; /* We have finished sending everything. */
tty_prepare_flip_string(tty, &data, count);
- if (!data){
+ if (!data) {
err("%s- kzalloc(%d) failed.", __func__, count);
return;
}
@@ -304,9 +305,10 @@ static void aircable_read(struct work_struct *work)
static int aircable_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
- struct usb_host_interface *iface_desc = serial->interface->cur_altsetting;
+ struct usb_host_interface *iface_desc = serial->interface->
+ cur_altsetting;
struct usb_endpoint_descriptor *endpoint;
- int num_bulk_out=0;
+ int num_bulk_out = 0;
int i;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
@@ -325,13 +327,13 @@ static int aircable_probe(struct usb_serial *serial,
return 0;
}
-static int aircable_attach (struct usb_serial *serial)
+static int aircable_attach(struct usb_serial *serial)
{
struct usb_serial_port *port = serial->port[0];
struct aircable_private *priv;
priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
- if (!priv){
+ if (!priv) {
err("%s- kmalloc(%Zd) failed.", __func__,
sizeof(struct aircable_private));
return -ENOMEM;
@@ -392,7 +394,7 @@ static int aircable_write(struct usb_serial_port *port,
usb_serial_debug_data(debug, &port->dev, __func__, count, source);
- if (!count){
+ if (!count) {
dbg("%s - write request of 0 bytes", __func__);
return count;
}
@@ -418,31 +420,31 @@ static void aircable_write_bulk_callback(struct urb *urb)
/* This has been taken from cypress_m8.c cypress_write_int_callback */
switch (status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
- port->write_urb_busy = 0;
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d",
+ __func__, status);
+ port->write_urb_busy = 0;
+ return;
+ default:
+ /* error in the urb, so we have to resubmit it */
+ dbg("%s - Overflow in write", __func__);
+ dbg("%s - nonzero write bulk status received: %d",
+ __func__, status);
+ port->write_urb->transfer_buffer_length = 1;
+ port->write_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting write urb, error %d\n",
+ __func__, result);
+ else
return;
- default:
- /* error in the urb, so we have to resubmit it */
- dbg("%s - Overflow in write", __func__);
- dbg("%s - nonzero write bulk status received: %d",
- __func__, status);
- port->write_urb->transfer_buffer_length = 1;
- port->write_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (result)
- dev_err(&urb->dev->dev,
- "%s - failed resubmitting write urb, error %d\n",
- __func__, result);
- else
- return;
}
port->write_urb_busy = 0;
@@ -472,11 +474,11 @@ static void aircable_read_bulk_callback(struct urb *urb)
dbg("%s - caught -EPROTO, resubmitting the urb",
__func__);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
- usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- aircable_read_bulk_callback, port);
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ aircable_read_bulk_callback, port);
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
@@ -490,7 +492,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
}
usb_serial_debug_data(debug, &port->dev, __func__,
- urb->actual_length,urb->transfer_buffer);
+ urb->actual_length, urb->transfer_buffer);
tty = port->tty;
if (tty && urb->actual_length) {
@@ -507,9 +509,9 @@ static void aircable_read_bulk_callback(struct urb *urb)
no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
- no_packages+=1;
+ no_packages++;
- for (i = 0; i < no_packages ;i++) {
+ for (i = 0; i < no_packages; i++) {
if (remaining > (HCI_COMPLETE_FRAME))
package_length = HCI_COMPLETE_FRAME;
else
@@ -529,7 +531,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
if (port->open_count) {
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
+ port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer,
port->read_urb->transfer_buffer_length,
aircable_read_bulk_callback, port);
@@ -602,7 +604,7 @@ static struct usb_serial_driver aircable_device = {
.unthrottle = aircable_unthrottle,
};
-static int __init aircable_init (void)
+static int __init aircable_init(void)
{
int retval;
retval = usb_serial_register(&aircable_device);
@@ -619,7 +621,7 @@ failed_usb_register:
return retval;
}
-static void __exit aircable_exit (void)
+static void __exit aircable_exit(void)
{
usb_deregister(&aircable_driver);
usb_serial_deregister(&aircable_device);
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 725b6b94c27..0798c14ce78 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -68,8 +68,9 @@ static int airprime_send_setup(struct usb_serial_port *port)
val |= 0x02;
return usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+ usb_rcvctrlpipe(serial->dev, 0),
+ 0x22, 0x21, val, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
}
return 0;
@@ -90,17 +91,19 @@ static void airprime_read_bulk_callback(struct urb *urb)
__func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__,
+ urb->actual_length, data);
tty = port->tty;
if (tty && urb->actual_length) {
- tty_insert_flip_string (tty, data, urb->actual_length);
- tty_flip_buffer_push (tty);
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_flip_buffer_push(tty);
}
- result = usb_submit_urb (urb, GFP_ATOMIC);
+ result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
__func__, result);
return;
}
@@ -115,7 +118,7 @@ static void airprime_write_bulk_callback(struct urb *urb)
dbg("%s - port %d", __func__, port->number);
/* free up the transfer buffer, as usb_free_urb() does not do this */
- kfree (urb->transfer_buffer);
+ kfree(urb->transfer_buffer);
if (status)
dbg("%s - nonzero write bulk status received: %d",
@@ -171,7 +174,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
}
usb_fill_bulk_urb(urb, serial->dev,
usb_rcvbulkpipe(serial->dev,
- port->bulk_out_endpointAddress),
+ port->bulk_out_endpointAddress),
buffer, buffer_size,
airprime_read_bulk_callback, port);
result = usb_submit_urb(urb, GFP_KERNEL);
@@ -183,7 +186,8 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
__func__, i, port->number, result);
goto errout;
}
- /* remember this urb so we can kill it when the port is closed */
+ /* remember this urb so we can kill it when the
+ port is closed */
priv->read_urbp[i] = urb;
}
@@ -192,22 +196,22 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
goto out;
errout:
- /* some error happened, cancel any submitted urbs and clean up anything that
- got allocated successfully */
+ /* some error happened, cancel any submitted urbs and clean up
+ anything that got allocated successfully */
while (i-- != 0) {
urb = priv->read_urbp[i];
buffer = urb->transfer_buffer;
- usb_kill_urb (urb);
- usb_free_urb (urb);
- kfree (buffer);
+ usb_kill_urb(urb);
+ usb_free_urb(urb);
+ kfree(buffer);
}
out:
return result;
}
-static void airprime_close(struct usb_serial_port *port, struct file * filp)
+static void airprime_close(struct usb_serial_port *port, struct file *filp)
{
struct airprime_private *priv = usb_get_serial_port_data(port);
int i;
@@ -220,16 +224,16 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp)
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected)
airprime_send_setup(port);
- mutex_lock(&port->serial->disc_mutex);
+ mutex_unlock(&port->serial->disc_mutex);
for (i = 0; i < NUM_READ_URBS; ++i) {
- usb_kill_urb (priv->read_urbp[i]);
- kfree (priv->read_urbp[i]->transfer_buffer);
- usb_free_urb (priv->read_urbp[i]);
+ usb_kill_urb(priv->read_urbp[i]);
+ kfree(priv->read_urbp[i]->transfer_buffer);
+ usb_free_urb(priv->read_urbp[i]);
}
/* free up private structure */
- kfree (priv);
+ kfree(priv);
usb_set_serial_port_data(port, NULL);
}
@@ -259,10 +263,10 @@ static int airprime_write(struct usb_serial_port *port,
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
dev_err(&port->dev, "no more free urbs\n");
- kfree (buffer);
+ kfree(buffer);
return -ENOMEM;
}
- memcpy (buffer, buf, count);
+ memcpy(buffer, buf, count);
usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
@@ -279,7 +283,7 @@ static int airprime_write(struct usb_serial_port *port,
"%s - usb_submit_urb(write bulk) failed with status = %d\n",
__func__, status);
count = status;
- kfree (buffer);
+ kfree(buffer);
} else {
spin_lock_irqsave(&priv->lock, flags);
++priv->outstanding_urbs;
@@ -287,7 +291,7 @@ static int airprime_write(struct usb_serial_port *port,
}
/* we are done with this urb, so let the host driver
* really free it when it is finished with it */
- usb_free_urb (urb);
+ usb_free_urb(urb);
return count;
}
@@ -315,8 +319,10 @@ static int __init airprime_init(void)
{
int retval;
- airprime_device.num_ports =
- (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
+ airprime_device.num_ports = endpoints;
+ if (endpoints < 0 || endpoints >= MAX_BULK_EPS)
+ airprime_device.num_ports = NUM_BULK_EPS;
+
retval = usb_serial_register(&airprime_device);
if (retval)
return retval;
@@ -341,6 +347,7 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled");
module_param(buffer_size, int, 0);
-MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
+MODULE_PARM_DESC(buffer_size,
+ "Size of the transfer buffers in bytes (default 4096)");
module_param(endpoints, int, 0);
MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 599ab2e548a..77895c8f8f3 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -24,7 +24,7 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
static int debug;
@@ -246,29 +246,29 @@ static void ark3116_set_termios(struct usb_serial_port *port,
baud = tty_get_baud_rate(port->tty);
switch (baud) {
- case 75:
- case 150:
- case 300:
- case 600:
- case 1200:
- case 1800:
- case 2400:
- case 4800:
- case 9600:
- case 19200:
- case 38400:
- case 57600:
- case 115200:
- case 230400:
- case 460800:
- /* Report the resulting rate back to the caller */
- tty_encode_baud_rate(port->tty, baud, baud);
- break;
- /* set 9600 as default (if given baudrate is invalid for example) */
- default:
- tty_encode_baud_rate(port->tty, 9600, 9600);
- case 0:
- baud = 9600;
+ case 75:
+ case 150:
+ case 300:
+ case 600:
+ case 1200:
+ case 1800:
+ case 2400:
+ case 4800:
+ case 9600:
+ case 19200:
+ case 38400:
+ case 57600:
+ case 115200:
+ case 230400:
+ case 460800:
+ /* Report the resulting rate back to the caller */
+ tty_encode_baud_rate(port->tty, baud, baud);
+ break;
+ /* set 9600 as default (if given baudrate is invalid for example) */
+ default:
+ tty_encode_baud_rate(port->tty, 9600, 9600);
+ case 0:
+ baud = 9600;
}
/*
@@ -380,19 +380,19 @@ static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
switch (cmd) {
case TIOCGSERIAL:
/* XXX: Some of these values are probably wrong. */
- memset(&serstruct, 0, sizeof (serstruct));
+ memset(&serstruct, 0, sizeof(serstruct));
serstruct.type = PORT_16654;
serstruct.line = port->serial->minor;
serstruct.port = port->number;
serstruct.custom_divisor = 0;
serstruct.baud_base = 460800;
- if (copy_to_user(user_arg, &serstruct, sizeof (serstruct)))
+ if (copy_to_user(user_arg, &serstruct, sizeof(serstruct)))
return -EFAULT;
return 0;
case TIOCSSERIAL:
- if (copy_from_user(&serstruct, user_arg, sizeof (serstruct)))
+ if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
return -EFAULT;
return 0;
default:
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index d947d955bce..ba28fdc9ccd 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -130,7 +130,7 @@ static int ch341_get_status(struct usb_device *dev)
return -ENOMEM;
r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
- if ( r < 0)
+ if (r < 0)
goto out;
/* Not having the datasheet for the CH341, we ignore the bytes returned
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c7329f43d9c..5b349ece724 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -133,6 +133,14 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 6da539ede0e..504edf8c3a3 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -40,6 +40,17 @@
/* AlphaMicro Components AMC-232USB01 device */
#define FTDI_AMC232_PID 0xFF00 /* Product Id */
+/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
+/* the VID is the standard ftdi vid (FTDI_VID) */
+#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */
+#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */
+#define FTDI_SCS_DEVICE_2_PID 0xD012
+#define FTDI_SCS_DEVICE_3_PID 0xD013
+#define FTDI_SCS_DEVICE_4_PID 0xD014
+#define FTDI_SCS_DEVICE_5_PID 0xD015
+#define FTDI_SCS_DEVICE_6_PID 0xD016
+#define FTDI_SCS_DEVICE_7_PID 0xD017
+
/* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */
#define FTDI_ACTZWAVE_PID 0xF2D0
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 6bcb82d3911..78f2f6db494 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1713,7 +1713,7 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
{
struct moschip_port *mos7840_port;
unsigned int mcr;
- unsigned int status;
+ int status;
dbg("%s - port %d", __func__, port->number);
@@ -1740,11 +1740,10 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
mos7840_port->shadowMCR = mcr;
- status = 0;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
if (status < 0) {
dbg("setting MODEM_CONTROL_REGISTER Failed\n");
- return -1;
+ return status;
}
return 0;
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 0f6d234d699..3d9249632ae 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -123,7 +123,8 @@ config USB_STORAGE_ALAUDA
config USB_STORAGE_ONETOUCH
bool "Support OneTouch Button on Maxtor Hard Drives"
- depends on USB_STORAGE && INPUT_EVDEV
+ depends on USB_STORAGE
+ depends on INPUT=y || INPUT=USB_STORAGE
help
Say Y here to include additional code to support the Maxtor OneTouch
USB hard drive's onetouch button.
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index d88824b3511..898e67d30e5 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -46,7 +46,7 @@ void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
}
memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
- memset(srb->cmnd, 0, sizeof(srb->cmnd));
+ memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
/* check if we support the command */
if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index 971d13dd5e6..3addcd8f827 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -292,6 +292,7 @@ struct isd200_info {
/* maximum number of LUNs supported */
unsigned char MaxLUNs;
+ unsigned char cmnd[BLK_MAX_CDB];
struct scsi_cmnd srb;
struct scatterlist sg;
};
@@ -450,6 +451,7 @@ static int isd200_action( struct us_data *us, int action,
memset(&ata, 0, sizeof(ata));
memset(&srb_dev, 0, sizeof(srb_dev));
+ srb->cmnd = info->cmnd;
srb->device = &srb_dev;
++srb->serial_number;
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index a28d49122e7..d617e8ae6b0 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -135,7 +135,7 @@ static int usu_probe(struct usb_interface *intf,
stat[type].fls |= USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
- task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
+ task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type);
if (IS_ERR(task)) {
rc = PTR_ERR(task);
printk(KERN_WARNING "libusual: "
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index dfd42fe9e5f..98b89ea9e31 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -38,7 +38,7 @@
#include "onetouch.h"
#include "debug.h"
-void onetouch_release_input(void *onetouch_);
+static void onetouch_release_input(void *onetouch_);
struct usb_onetouch {
char name[128];
@@ -223,7 +223,7 @@ int onetouch_connect_input(struct us_data *ss)
return error;
}
-void onetouch_release_input(void *onetouch_)
+static void onetouch_release_input(void *onetouch_)
{
struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 732bf52a775..a0ed889230a 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -44,7 +44,8 @@
* running with this patch.
* Send your submission to either Phil Dibowitz <phil@ipom.com> or
* Alan Stern <stern@rowland.harvard.edu>, and don't forget to CC: the
- * USB development list <linux-usb-devel@lists.sourceforge.net>.
+ * USB development list <linux-usb@vger.kernel.org> and the USB storage list
+ * <usb-storage@lists.one-eyed-alien.net>
*/
/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
@@ -557,6 +558,13 @@ UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999,
US_FL_SINGLE_LUN),
#endif
+/* Reported by Dmitry Khlystov <adminimus@gmail.com> */
+UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220,
+ "Samsung",
+ "YP-U3",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64),
+
/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133,
"Belkin",
@@ -1200,6 +1208,17 @@ UNUSUAL_DEV( 0x084d, 0x0011, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_BULK32),
+/* Andrew Lunn <andrew@lunn.ch>
+ * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
+ * on LUN 4.
+ * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera"
+*/
+UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200,
+ "PanDigital",
+ "Photo Frame",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE),
+
/* Submitted by Jan De Luyck <lkml@kcore.org> */
UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000,
"CITIZEN",
@@ -1342,6 +1361,13 @@ UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY),
+/* Reported by Rohan Hart <rohan.hart17@gmail.com> */
+UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010,
+ "INTOVA",
+ "Pixtreme",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/*
* Entry for Jenoptik JD 5200z3
*
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index a856effad3b..e268aacb773 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -539,7 +539,8 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
" has %s in unusual_devs.h (kernel"
" %s)\n"
" Please send a copy of this message to "
- "<linux-usb-devel@lists.sourceforge.net>\n",
+ "<linux-usb@vger.kernel.org> and "
+ "<usb-storage@lists.one-eyed-alien.net>\n",
le16_to_cpu(ddesc->idVendor),
le16_to_cpu(ddesc->idProduct),
le16_to_cpu(ddesc->bcdDevice),
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index b535483bc55..13866789b35 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -80,19 +80,51 @@ static void add_status(struct virtio_device *dev, unsigned status)
dev->config->set_status(dev, dev->config->get_status(dev) | status);
}
+void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
+ unsigned int fbit)
+{
+ unsigned int i;
+ struct virtio_driver *drv = container_of(vdev->dev.driver,
+ struct virtio_driver, driver);
+
+ for (i = 0; i < drv->feature_table_size; i++)
+ if (drv->feature_table[i] == fbit)
+ return;
+ BUG();
+}
+EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
+
static int virtio_dev_probe(struct device *_d)
{
- int err;
+ int err, i;
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
struct virtio_driver *drv = container_of(dev->dev.driver,
struct virtio_driver, driver);
+ u32 device_features;
+ /* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER);
+
+ /* Figure out what features the device supports. */
+ device_features = dev->config->get_features(dev);
+
+ /* Features supported by both device and driver into dev->features. */
+ memset(dev->features, 0, sizeof(dev->features));
+ for (i = 0; i < drv->feature_table_size; i++) {
+ unsigned int f = drv->feature_table[i];
+ BUG_ON(f >= 32);
+ if (device_features & (1 << f))
+ set_bit(f, dev->features);
+ }
+
err = drv->probe(dev);
if (err)
add_status(dev, VIRTIO_CONFIG_S_FAILED);
- else
+ else {
add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
+ /* They should never have set feature bits beyond 32 */
+ dev->config->set_features(dev, dev->features[0]);
+ }
return err;
}
@@ -114,6 +146,8 @@ static int virtio_dev_remove(struct device *_d)
int register_virtio_driver(struct virtio_driver *driver)
{
+ /* Catch this early. */
+ BUG_ON(driver->feature_table_size && !driver->feature_table);
driver->driver.bus = &virtio_bus;
driver->driver.probe = virtio_dev_probe;
driver->driver.remove = virtio_dev_remove;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 0b3efc31ee6..bfef604160d 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -155,9 +155,9 @@ static void virtballoon_changed(struct virtio_device *vdev)
static inline s64 towards_target(struct virtio_balloon *vb)
{
u32 v;
- __virtio_config_val(vb->vdev,
- offsetof(struct virtio_balloon_config, num_pages),
- &v);
+ vb->vdev->config->get(vb->vdev,
+ offsetof(struct virtio_balloon_config, num_pages),
+ &v, sizeof(v));
return v - vb->num_pages;
}
@@ -227,7 +227,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
}
vb->tell_host_first
- = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+ = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
return 0;
@@ -259,7 +259,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
kfree(vb);
}
+static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
+
static struct virtio_driver virtio_balloon = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index c0df924766a..27e9fc9117c 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -87,23 +87,22 @@ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
return container_of(vdev, struct virtio_pci_device, vdev);
}
-/* virtio config->feature() implementation */
-static bool vp_feature(struct virtio_device *vdev, unsigned bit)
+/* virtio config->get_features() implementation */
+static u32 vp_get_features(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ /* When someone needs more than 32 feature bits, we'll need to
+ * steal a bit to indicate that the rest are somewhere else. */
+ return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
+
+/* virtio config->set_features() implementation */
+static void vp_set_features(struct virtio_device *vdev, u32 features)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- u32 mask;
-
- /* Since this function is supposed to have the side effect of
- * enabling a queried feature, we simulate that by doing a read
- * from the host feature bitmask and then writing to the guest
- * feature bitmask */
- mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
- if (mask & (1 << bit)) {
- mask |= (1 << bit);
- iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
- }
- return !!(mask & (1 << bit));
+ iowrite32(features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
}
/* virtio config->get() implementation */
@@ -145,14 +144,14 @@ static void vp_set_status(struct virtio_device *vdev, u8 status)
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
/* We should never be setting status to 0. */
BUG_ON(status == 0);
- return iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+ iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
}
static void vp_reset(struct virtio_device *vdev)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
/* 0 status means a reset. */
- return iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+ iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
}
/* the notify function used when creating a virt queue */
@@ -293,7 +292,6 @@ static void vp_del_vq(struct virtqueue *vq)
}
static struct virtio_config_ops virtio_pci_config_ops = {
- .feature = vp_feature,
.get = vp_get,
.set = vp_set,
.get_status = vp_get_status,
@@ -301,6 +299,8 @@ static struct virtio_config_ops virtio_pci_config_ops = {
.reset = vp_reset,
.find_vq = vp_find_vq,
.del_vq = vp_del_vq,
+ .get_features = vp_get_features,
+ .set_features = vp_set_features,
};
/* the PCI probing function */
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index c2fa5c63081..937a49d6772 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -184,6 +184,11 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
START_USE(vq);
+ if (unlikely(vq->broken)) {
+ END_USE(vq);
+ return NULL;
+ }
+
if (!more_used(vq)) {
pr_debug("No more buffers in queue\n");
END_USE(vq);
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index f42be069e08..977ef208c05 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -57,9 +57,6 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
* anonymous inode, and a dentry that describe the "class"
* of the file
*
- * @pfd: [out] pointer to the file descriptor
- * @dpinode: [out] pointer to the inode
- * @pfile: [out] pointer to the file struct
* @name: [in] name of the "class" of the new file
* @fops [in] file operations for the new file
* @priv [in] private data for the new file (will be file's private_data)
@@ -68,10 +65,9 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
* that do not need to have a full-fledged inode in order to operate correctly.
* All the files created with anon_inode_getfd() will share a single inode,
* hence saving memory and avoiding code duplication for the file/inode/dentry
- * setup.
+ * setup. Returns new descriptor or -error.
*/
-int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
- const char *name, const struct file_operations *fops,
+int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv)
{
struct qstr this;
@@ -125,10 +121,7 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
fd_install(fd, file);
- *pfd = fd;
- *pinode = anon_inode_inode;
- *pfile = file;
- return 0;
+ return fd;
err_dput:
dput(dentry);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index d96e5c14a9c..894fee54d4d 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -73,8 +73,8 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
status = 0;
done:
DPRINTK("returning = %d", status);
- mntput(mnt);
dput(dentry);
+ mntput(mnt);
return status;
}
@@ -333,7 +333,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
/* Can we expire this guy */
if (autofs4_can_expire(dentry, timeout, do_now)) {
expired = dentry;
- break;
+ goto found;
}
goto next;
}
@@ -352,7 +352,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
inf->flags |= AUTOFS_INF_EXPIRING;
spin_unlock(&sbi->fs_lock);
expired = dentry;
- break;
+ goto found;
}
spin_unlock(&sbi->fs_lock);
/*
@@ -363,7 +363,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
if (expired) {
dput(dentry);
- break;
+ goto found;
}
}
next:
@@ -371,18 +371,16 @@ next:
spin_lock(&dcache_lock);
next = next->next;
}
-
- if (expired) {
- DPRINTK("returning %p %.*s",
- expired, (int)expired->d_name.len, expired->d_name.name);
- spin_lock(&dcache_lock);
- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
- spin_unlock(&dcache_lock);
- return expired;
- }
spin_unlock(&dcache_lock);
-
return NULL;
+
+found:
+ DPRINTK("returning %p %.*s",
+ expired, (int)expired->d_name.len, expired->d_name.name);
+ spin_lock(&dcache_lock);
+ list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
+ spin_unlock(&dcache_lock);
+ return expired;
}
/* Perform an expiry operation */
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index aa4c5ff8a40..edf5b6bddb5 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -146,17 +146,17 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
if (d_mountpoint(dentry)) {
struct file *fp = NULL;
- struct vfsmount *fp_mnt = mntget(mnt);
- struct dentry *fp_dentry = dget(dentry);
+ struct path fp_path = { .dentry = dentry, .mnt = mnt };
- if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) {
- dput(fp_dentry);
- mntput(fp_mnt);
+ path_get(&fp_path);
+
+ if (!autofs4_follow_mount(&fp_path.mnt, &fp_path.dentry)) {
+ path_put(&fp_path);
dcache_dir_close(inode, file);
goto out;
}
- fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
+ fp = dentry_open(fp_path.dentry, fp_path.mnt, file->f_flags);
status = PTR_ERR(fp);
if (IS_ERR(fp)) {
dcache_dir_close(inode, file);
@@ -242,7 +242,8 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
- int status = 0;
+ struct dentry *new;
+ int status;
/* Block on any pending expiry here; invalidate the dentry
when expiration is done to trigger mount request with a new
@@ -318,7 +319,28 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags)
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
spin_unlock(&dentry->d_lock);
- return status;
+
+ /*
+ * The dentry that is passed in from lookup may not be the one
+ * we end up using, as mkdir can create a new one. If this
+ * happens, and another process tries the lookup at the same time,
+ * it will set the PENDING flag on this new dentry, but add itself
+ * to our waitq. Then, if after the lookup succeeds, the first
+ * process that requested the mount performs another lookup of the
+ * same directory, it will show up as still pending! So, we need
+ * to redo the lookup here and clear pending on that dentry.
+ */
+ if (d_unhashed(dentry)) {
+ new = d_lookup(dentry->d_parent, &dentry->d_name);
+ if (new) {
+ spin_lock(&new->d_lock);
+ new->d_flags &= ~DCACHE_AUTOFS_PENDING;
+ spin_unlock(&new->d_lock);
+ dput(new);
+ }
+ }
+
+ return 0;
}
/* For autofs direct mounts the follow link triggers the mount */
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 1fe28e4754c..75e5955c3f6 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -171,7 +171,7 @@ static int autofs4_getpath(struct autofs_sb_info *sbi,
for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent)
len += tmp->d_name.len + 1;
- if (--len > NAME_MAX) {
+ if (!len || --len > NAME_MAX) {
spin_unlock(&dcache_lock);
return 0;
}
diff --git a/fs/compat.c b/fs/compat.c
index 139dc93c092..332a869d2c5 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -24,6 +24,7 @@
#include <linux/fcntl.h>
#include <linux/namei.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/vfs.h>
#include <linux/ioctl.h>
#include <linux/init.h>
diff --git a/fs/dnotify.c b/fs/dnotify.c
index eaecc4cfe54..676073b8dda 100644
--- a/fs/dnotify.c
+++ b/fs/dnotify.c
@@ -20,7 +20,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
-#include <linux/file.h>
+#include <linux/fdtable.h>
int dir_notify_enable __read_mostly = 1;
diff --git a/fs/eventfd.c b/fs/eventfd.c
index a9f130cd50a..343942deeec 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -200,10 +200,8 @@ struct file *eventfd_fget(int fd)
asmlinkage long sys_eventfd(unsigned int count)
{
- int error, fd;
+ int fd;
struct eventfd_ctx *ctx;
- struct file *file;
- struct inode *inode;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -216,12 +214,9 @@ asmlinkage long sys_eventfd(unsigned int count)
* When we call this, the initialization must be complete, since
* anon_inode_getfd() will install the fd.
*/
- error = anon_inode_getfd(&fd, &inode, &file, "[eventfd]",
- &eventfd_fops, ctx);
- if (!error)
- return fd;
-
- kfree(ctx);
- return error;
+ fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx);
+ if (fd < 0)
+ kfree(ctx);
+ return fd;
}
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 221086fef17..990c01d2d66 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -1050,8 +1050,6 @@ asmlinkage long sys_epoll_create(int size)
{
int error, fd = -1;
struct eventpoll *ep;
- struct inode *inode;
- struct file *file;
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
current, size));
@@ -1061,29 +1059,24 @@ asmlinkage long sys_epoll_create(int size)
* structure ( "struct eventpoll" ).
*/
error = -EINVAL;
- if (size <= 0 || (error = ep_alloc(&ep)) != 0)
+ if (size <= 0 || (error = ep_alloc(&ep)) < 0) {
+ fd = error;
goto error_return;
+ }
/*
* Creates all the items needed to setup an eventpoll file. That is,
- * a file structure, and inode and a free file descriptor.
+ * a file structure and a free file descriptor.
*/
- error = anon_inode_getfd(&fd, &inode, &file, "[eventpoll]",
- &eventpoll_fops, ep);
- if (error)
- goto error_free;
+ fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep);
+ if (fd < 0)
+ ep_free(ep);
+error_return:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
current, size, fd));
return fd;
-
-error_free:
- ep_free(ep);
-error_return:
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
- current, size, error));
- return error;
}
/*
diff --git a/fs/exec.c b/fs/exec.c
index 9f9f931ef94..aeaa9791d8b 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/mman.h>
#include <linux/a.out.h>
#include <linux/stat.h>
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 3f3ac630ccd..bfd776509a7 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -9,6 +9,7 @@
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/capability.h>
#include <linux/dnotify.h>
#include <linux/smp_lock.h>
diff --git a/fs/file.c b/fs/file.c
index 5110acb1c9e..4c6f0ea12c4 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
@@ -149,8 +150,16 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
nr /= (1024 / sizeof(struct file *));
nr = roundup_pow_of_two(nr + 1);
nr *= (1024 / sizeof(struct file *));
- if (nr > sysctl_nr_open)
- nr = sysctl_nr_open;
+ /*
+ * Note that this can drive nr *below* what we had passed if sysctl_nr_open
+ * had been set lower between the check in expand_files() and here. Deal
+ * with that in caller, it's cheaper that way.
+ *
+ * We make sure that nr remains a multiple of BITS_PER_LONG - otherwise
+ * bitmaps handling below becomes unpleasant, to put it mildly...
+ */
+ if (unlikely(nr > sysctl_nr_open))
+ nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1;
fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
if (!fdt)
@@ -199,6 +208,16 @@ static int expand_fdtable(struct files_struct *files, int nr)
if (!new_fdt)
return -ENOMEM;
/*
+ * extremely unlikely race - sysctl_nr_open decreased between the check in
+ * caller and alloc_fdtable(). Cheaper to catch it here...
+ */
+ if (unlikely(new_fdt->max_fds <= nr)) {
+ free_fdarr(new_fdt);
+ free_fdset(new_fdt);
+ kfree(new_fdt);
+ return -EMFILE;
+ }
+ /*
* Check again since another task may have expanded the fd table while
* we dropped the lock
*/
diff --git a/fs/file_table.c b/fs/file_table.c
index 7a0a9b87225..83084225b4c 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -8,6 +8,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 9ced35b0068..f28cf8b46f8 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -934,7 +934,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
- npages = min(max(npages, 1), FUSE_MAX_PAGES_PER_REQ);
+ npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ);
down_read(&current->mm->mmap_sem);
npages = get_user_pages(current, current->mm, user_addr, npages, write,
0, req->pages, NULL);
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index d58f845ccb8..c5e1450d79f 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -46,7 +46,7 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
- struct jffs2_inode_cache *ic)
+ struct jffs2_inode_cache *ic)
{
struct jffs2_full_dirent *fd;
@@ -68,11 +68,17 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
continue;
}
- if (child_ic->nlink++ && fd->type == DT_DIR) {
- JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
- fd->name, fd->ino, ic->ino);
- /* TODO: What do we do about it? */
- }
+ if (fd->type == DT_DIR) {
+ if (child_ic->pino_nlink) {
+ JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
+ fd->name, fd->ino, ic->ino);
+ /* TODO: What do we do about it? */
+ } else {
+ child_ic->pino_nlink = ic->ino;
+ }
+ } else
+ child_ic->pino_nlink++;
+
dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
/* Can't free scan_dents so far. We might need them in pass 2 */
}
@@ -125,7 +131,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
dbg_fsbuild("pass 2 starting\n");
for_each_inode(i, c, ic) {
- if (ic->nlink)
+ if (ic->pino_nlink)
continue;
jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
@@ -232,16 +238,19 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c,
/* Reduce nlink of the child. If it's now zero, stick it on the
dead_fds list to be cleaned up later. Else just free the fd */
- child_ic->nlink--;
+ if (fd->type == DT_DIR)
+ child_ic->pino_nlink = 0;
+ else
+ child_ic->pino_nlink--;
- if (!child_ic->nlink) {
- dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n",
+ if (!child_ic->pino_nlink) {
+ dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
fd->ino, fd->name);
fd->next = *dead_fds;
*dead_fds = fd;
} else {
dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
- fd->ino, fd->name, child_ic->nlink);
+ fd->ino, fd->name, child_ic->pino_nlink);
jffs2_free_full_dirent(fd);
}
}
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index c63e7a96af0..c0c141f6fde 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -208,6 +208,13 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
f = JFFS2_INODE_INFO(inode);
dir_f = JFFS2_INODE_INFO(dir_i);
+ /* jffs2_do_create() will want to lock it, _after_ reserving
+ space and taking c-alloc_sem. If we keep it locked here,
+ lockdep gets unhappy (although it's a false positive;
+ nothing else will be looking at this inode yet so there's
+ no chance of AB-BA deadlock involving its f->sem). */
+ mutex_unlock(&f->sem);
+
ret = jffs2_do_create(c, dir_f, f, ri,
dentry->d_name.name, dentry->d_name.len);
if (ret)
@@ -219,7 +226,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
d_instantiate(dentry, inode);
D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
- inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
+ inode->i_ino, inode->i_mode, inode->i_nlink,
+ f->inocache->pino_nlink, inode->i_mapping->nrpages));
return 0;
fail:
@@ -243,7 +251,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
dentry->d_name.len, dead_f, now);
if (dead_f->inocache)
- dentry->d_inode->i_nlink = dead_f->inocache->nlink;
+ dentry->d_inode->i_nlink = dead_f->inocache->pino_nlink;
if (!ret)
dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
return ret;
@@ -276,7 +284,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
if (!ret) {
mutex_lock(&f->sem);
- old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
+ old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink;
mutex_unlock(&f->sem);
d_instantiate(dentry, old_dentry->d_inode);
dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
@@ -493,11 +501,14 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
inode->i_op = &jffs2_dir_inode_operations;
inode->i_fop = &jffs2_dir_operations;
- /* Directories get nlink 2 at start */
- inode->i_nlink = 2;
f = JFFS2_INODE_INFO(inode);
+ /* Directories get nlink 2 at start */
+ inode->i_nlink = 2;
+ /* but ic->pino_nlink is the parent ino# */
+ f->inocache->pino_nlink = dir_i->i_ino;
+
ri->data_crc = cpu_to_je32(0);
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
@@ -594,17 +605,25 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
{
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
+ struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
struct jffs2_full_dirent *fd;
int ret;
+ uint32_t now = get_seconds();
for (fd = f->dents ; fd; fd = fd->next) {
if (fd->ino)
return -ENOTEMPTY;
}
- ret = jffs2_unlink(dir_i, dentry);
- if (!ret)
+
+ ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
+ dentry->d_name.len, f, now);
+ if (!ret) {
+ dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
+ clear_nlink(dentry->d_inode);
drop_nlink(dir_i);
+ }
return ret;
}
@@ -817,7 +836,10 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
inode which didn't exist. */
if (victim_f->inocache) {
mutex_lock(&victim_f->sem);
- victim_f->inocache->nlink--;
+ if (S_ISDIR(new_dentry->d_inode->i_mode))
+ victim_f->inocache->pino_nlink = 0;
+ else
+ victim_f->inocache->pino_nlink--;
mutex_unlock(&victim_f->sem);
}
}
@@ -838,8 +860,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
mutex_lock(&f->sem);
inc_nlink(old_dentry->d_inode);
- if (f->inocache)
- f->inocache->nlink++;
+ if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode))
+ f->inocache->pino_nlink++;
mutex_unlock(&f->sem);
printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 25a640e566d..dddb2a6c9e2 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -294,7 +294,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
break;
#endif
default:
- if (ic->nodes == (void *)ic && ic->nlink == 0)
+ if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
jffs2_del_ino_cache(c, ic);
}
}
@@ -332,7 +332,8 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (c->mtd->point) {
unsigned long *wordebuf;
- ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf);
+ ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size,
+ &retlen, &ebuf, NULL);
if (ret) {
D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
goto do_flash_read;
@@ -340,7 +341,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (retlen < c->sector_size) {
/* Don't muck about if it won't let us point to the whole erase sector */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
- c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen);
+ c->mtd->unpoint(c->mtd, jeb->offset, retlen);
goto do_flash_read;
}
wordebuf = ebuf-sizeof(*wordebuf);
@@ -349,7 +350,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (*++wordebuf != ~0)
break;
} while(--retlen);
- c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size);
+ c->mtd->unpoint(c->mtd, jeb->offset, c->sector_size);
if (retlen) {
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
*wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 3eb1c84b0a3..086c4383022 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -273,7 +273,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
- inode->i_nlink = f->inocache->nlink;
+ inode->i_nlink = f->inocache->pino_nlink;
inode->i_blocks = (inode->i_size + 511) >> 9;
@@ -286,13 +286,12 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
case S_IFDIR:
{
struct jffs2_full_dirent *fd;
+ inode->i_nlink = 2; /* parent and '.' */
for (fd=f->dents; fd; fd = fd->next) {
if (fd->type == DT_DIR && fd->ino)
inc_nlink(inode);
}
- /* and '..' */
- inc_nlink(inode);
/* Root dir gets i_nlink 3 for some reason */
if (inode->i_ino == 1)
inc_nlink(inode);
@@ -586,11 +585,12 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c,
}
struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
- int inum, int nlink)
+ int inum, int unlinked)
{
struct inode *inode;
struct jffs2_inode_cache *ic;
- if (!nlink) {
+
+ if (unlinked) {
/* The inode has zero nlink but its nodes weren't yet marked
obsolete. This has to be because we're still waiting for
the final (close() and) iput() to happen.
@@ -638,8 +638,8 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
return ERR_CAST(inode);
}
if (is_bad_inode(inode)) {
- printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
- inum, nlink);
+ printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. unlinked %d\n",
+ inum, unlinked);
/* NB. This will happen again. We need to do something appropriate here. */
iput(inode);
return ERR_PTR(-EIO);
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index bad005664e3..090c556ffed 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -161,8 +161,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
continue;
}
- if (!ic->nlink) {
- D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
+ if (!ic->pino_nlink) {
+ D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink/pino zero\n",
ic->ino));
spin_unlock(&c->inocache_lock);
jffs2_xattr_delete_inode(c, ic);
@@ -398,10 +398,10 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
it's vaguely possible. */
inum = ic->ino;
- nlink = ic->nlink;
+ nlink = ic->pino_nlink;
spin_unlock(&c->inocache_lock);
- f = jffs2_gc_fetch_inode(c, inum, nlink);
+ f = jffs2_gc_fetch_inode(c, inum, !nlink);
if (IS_ERR(f)) {
ret = PTR_ERR(f);
goto release_sem;
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 8219df6eb6d..1750445556c 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -177,7 +177,10 @@ struct jffs2_inode_cache {
#ifdef CONFIG_JFFS2_FS_XATTR
struct jffs2_xattr_ref *xref;
#endif
- int nlink;
+ uint32_t pino_nlink; /* Directories store parent inode
+ here; other inodes store nlink.
+ Zero always means that it's
+ completely unlinked. */
};
/* Inode states for 'state' above. We need the 'GC' state to prevent
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 9df8f3ef20d..a9bf9603c1b 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -709,7 +709,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
break;
#endif
default:
- if (ic->nodes == (void *)ic && ic->nlink == 0)
+ if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
jffs2_del_ino_cache(c, ic);
break;
}
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 1b10d259409..2cc866cf134 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -187,7 +187,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
void jffs2_gc_release_inode(struct jffs2_sb_info *c,
struct jffs2_inode_info *f);
struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
- int inum, int nlink);
+ int inum, int unlinked);
unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
struct jffs2_inode_info *f,
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 4cb4d76de07..6ca08ad887c 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -63,10 +63,11 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
/* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
* adding and jffs2_flash_read_end() interface. */
if (c->mtd->point) {
- err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
+ err = c->mtd->point(c->mtd, ofs, len, &retlen,
+ (void **)&buffer, NULL);
if (!err && retlen < len) {
JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
- c->mtd->unpoint(c->mtd, buffer, ofs, retlen);
+ c->mtd->unpoint(c->mtd, ofs, retlen);
} else if (err)
JFFS2_WARNING("MTD point failed: error code %d.\n", err);
else
@@ -100,7 +101,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
kfree(buffer);
#ifndef __ECOS
else
- c->mtd->unpoint(c->mtd, buffer, ofs, len);
+ c->mtd->unpoint(c->mtd, ofs, len);
#endif
if (crc != tn->data_crc) {
@@ -136,7 +137,7 @@ free_out:
kfree(buffer);
#ifndef __ECOS
else
- c->mtd->unpoint(c->mtd, buffer, ofs, len);
+ c->mtd->unpoint(c->mtd, ofs, len);
#endif
return err;
}
@@ -1123,7 +1124,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
size_t retlen;
int ret;
- dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink);
+ dbg_readinode("ino #%u pino/nlink is %d\n", f->inocache->ino,
+ f->inocache->pino_nlink);
memset(&rii, 0, sizeof(rii));
@@ -1358,7 +1360,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
}
dbg_readinode("creating inocache for root inode\n");
memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
- f->inocache->ino = f->inocache->nlink = 1;
+ f->inocache->ino = f->inocache->pino_nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->state = INO_STATE_READING;
jffs2_add_ino_cache(c, f->inocache);
@@ -1401,7 +1403,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
jffs2_clear_acl(f);
jffs2_xattr_delete_inode(c, f->inocache);
mutex_lock(&f->sem);
- deleted = f->inocache && !f->inocache->nlink;
+ deleted = f->inocache && !f->inocache->pino_nlink;
if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 272872d27fd..1d437de1e9a 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -97,11 +97,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
size_t pointlen;
if (c->mtd->point) {
- ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf);
+ ret = c->mtd->point(c->mtd, 0, c->mtd->size, &pointlen,
+ (void **)&flashbuf, NULL);
if (!ret && pointlen < c->mtd->size) {
/* Don't muck about if it won't let us point to the whole flash */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
- c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen);
+ c->mtd->unpoint(c->mtd, 0, pointlen);
flashbuf = NULL;
}
if (ret)
@@ -267,7 +268,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
kfree(flashbuf);
#ifndef __ECOS
else
- c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
+ c->mtd->unpoint(c->mtd, 0, c->mtd->size);
#endif
if (s)
kfree(s);
@@ -940,7 +941,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin
ic->nodes = (void *)ic;
jffs2_add_ino_cache(c, ic);
if (ino == 1)
- ic->nlink = 1;
+ ic->pino_nlink = 1;
return ic;
}
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index f3353df178e..7da69eae49e 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -31,11 +31,12 @@ static struct kmem_cache *jffs2_inode_cachep;
static struct inode *jffs2_alloc_inode(struct super_block *sb)
{
- struct jffs2_inode_info *ei;
- ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
- if (!ei)
+ struct jffs2_inode_info *f;
+
+ f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
+ if (!f)
return NULL;
- return &ei->vfs_inode;
+ return &f->vfs_inode;
}
static void jffs2_destroy_inode(struct inode *inode)
@@ -45,10 +46,10 @@ static void jffs2_destroy_inode(struct inode *inode)
static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo)
{
- struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
+ struct jffs2_inode_info *f = foo;
- mutex_init(&ei->sem);
- inode_init_once(&ei->vfs_inode);
+ mutex_init(&f->sem);
+ inode_init_once(&f->vfs_inode);
}
static int jffs2_sync_fs(struct super_block *sb, int wait)
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 8de52b60767..0e78b00035e 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -494,7 +494,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
/* If it's an in-core inode, then we have to adjust any
full_dirent or full_dnode structure to point to the
new version instead of the old */
- f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink);
+ f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink);
if (IS_ERR(f)) {
/* Should never happen; it _must_ be present */
JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n",
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 665fce9797d..ca29440e943 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -19,7 +19,8 @@
#include "compr.h"
-int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri)
+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+ uint32_t mode, struct jffs2_raw_inode *ri)
{
struct jffs2_inode_cache *ic;
@@ -31,7 +32,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
memset(ic, 0, sizeof(*ic));
f->inocache = ic;
- f->inocache->nlink = 1;
+ f->inocache->pino_nlink = 1; /* Will be overwritten shortly for directories */
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->state = INO_STATE_PRESENT;
@@ -438,10 +439,10 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
JFFS2_SUMMARY_INODE_SIZE);
D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
- if (ret) {
- mutex_unlock(&f->sem);
+ if (ret)
return ret;
- }
+
+ mutex_lock(&f->sem);
ri->data_crc = cpu_to_je32(0);
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
@@ -635,9 +636,9 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
jffs2_mark_node_obsolete(c, fd->raw);
jffs2_free_full_dirent(fd);
}
- }
-
- dead_f->inocache->nlink--;
+ dead_f->inocache->pino_nlink = 0;
+ } else
+ dead_f->inocache->pino_nlink--;
/* NB: Caller must set inode nlink if appropriate */
mutex_unlock(&dead_f->sem);
}
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 574cb7532d6..082e844ab2d 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -592,7 +592,7 @@ void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache
When an inode with XATTR is removed, those XATTRs must be removed. */
struct jffs2_xattr_ref *ref, *_ref;
- if (!ic || ic->nlink > 0)
+ if (!ic || ic->pino_nlink > 0)
return;
down_write(&c->xattr_sem);
@@ -829,7 +829,7 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
ref->xd and ref->ic are not valid yet. */
xd = jffs2_find_xattr_datum(c, ref->xid);
ic = jffs2_get_ino_cache(c, ref->ino);
- if (!xd || !ic || !ic->nlink) {
+ if (!xd || !ic || !ic->pino_nlink) {
dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
ref->ino, ref->xid, ref->xseqno);
ref->xseqno |= XREF_DELETE_MARKER;
diff --git a/fs/locks.c b/fs/locks.c
index 44d9a6a7ec5..663c069b59b 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -116,6 +116,7 @@
#include <linux/capability.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/fs/ocfs2/cluster/sys.c b/fs/ocfs2/cluster/sys.c
index 98429fd6849..bc702dab5d1 100644
--- a/fs/ocfs2/cluster/sys.c
+++ b/fs/ocfs2/cluster/sys.c
@@ -65,7 +65,7 @@ int o2cb_sys_init(void)
{
int ret;
- o2cb_kset = kset_create_and_add("o2cb", NULL, NULL);
+ o2cb_kset = kset_create_and_add("o2cb", NULL, fs_kobj);
if (!o2cb_kset)
return -ENOMEM;
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c
index 5f6d858770a..1b81dcba175 100644
--- a/fs/ocfs2/dlm/dlmdebug.c
+++ b/fs/ocfs2/dlm/dlmdebug.c
@@ -44,7 +44,8 @@
#define MLOG_MASK_PREFIX ML_DLM
#include "cluster/masklog.h"
-int stringify_lockname(const char *lockname, int locklen, char *buf, int len);
+static int stringify_lockname(const char *lockname, int locklen, char *buf,
+ int len);
void dlm_print_one_lock_resource(struct dlm_lock_resource *res)
{
@@ -251,7 +252,8 @@ EXPORT_SYMBOL_GPL(dlm_errname);
*
* For more on lockname formats, please refer to dlmglue.c and ocfs2_lockid.h.
*/
-int stringify_lockname(const char *lockname, int locklen, char *buf, int len)
+static int stringify_lockname(const char *lockname, int locklen, char *buf,
+ int len)
{
int out = 0;
__be64 inode_blkno_be;
@@ -368,7 +370,7 @@ static void dlm_debug_free(struct kref *kref)
kfree(dc);
}
-void dlm_debug_put(struct dlm_debug_ctxt *dc)
+static void dlm_debug_put(struct dlm_debug_ctxt *dc)
{
if (dc)
kref_put(&dc->debug_refcnt, dlm_debug_free);
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 9154c82d325..57e0d30cde9 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1048,6 +1048,10 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
mlog_entry("(0x%p, '%.*s')\n", dentry,
dentry->d_name.len, dentry->d_name.name);
+ /* ensuring we don't even attempt to truncate a symlink */
+ if (S_ISLNK(inode->i_mode))
+ attr->ia_valid &= ~ATTR_SIZE;
+
if (attr->ia_valid & ATTR_MODE)
mlog(0, "mode change: %d\n", attr->ia_mode);
if (attr->ia_valid & ATTR_UID)
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index ce0dc147602..be774bdc8b3 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -260,7 +260,7 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
bh = osb->local_alloc_bh;
alloc = (struct ocfs2_dinode *) bh->b_data;
- alloc_copy = kmalloc(bh->b_size, GFP_KERNEL);
+ alloc_copy = kmalloc(bh->b_size, GFP_NOFS);
if (!alloc_copy) {
status = -ENOMEM;
goto out_commit;
@@ -931,7 +931,7 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
* local alloc shutdown won't try to double free main bitmap
* bits. Make a copy so the sync function knows which bits to
* free. */
- alloc_copy = kmalloc(osb->local_alloc_bh->b_size, GFP_KERNEL);
+ alloc_copy = kmalloc(osb->local_alloc_bh->b_size, GFP_NOFS);
if (!alloc_copy) {
status = -ENOMEM;
mlog_errno(status);
diff --git a/fs/ocfs2/stack_o2cb.c b/fs/ocfs2/stack_o2cb.c
index ac1d74c63bf..bbd1667aa7d 100644
--- a/fs/ocfs2/stack_o2cb.c
+++ b/fs/ocfs2/stack_o2cb.c
@@ -385,7 +385,7 @@ static int o2cb_cluster_this_node(unsigned int *node)
return 0;
}
-struct ocfs2_stack_operations o2cb_stack_ops = {
+static struct ocfs2_stack_operations o2cb_stack_ops = {
.connect = o2cb_cluster_connect,
.disconnect = o2cb_cluster_disconnect,
.hangup = o2cb_cluster_hangup,
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c
index 7428663f9cb..b503772cd0e 100644
--- a/fs/ocfs2/stack_user.c
+++ b/fs/ocfs2/stack_user.c
@@ -635,7 +635,7 @@ static const struct file_operations ocfs2_control_fops = {
.owner = THIS_MODULE,
};
-struct miscdevice ocfs2_control_device = {
+static struct miscdevice ocfs2_control_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "ocfs2_control",
.fops = &ocfs2_control_fops,
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index 7134007ba22..ba9dbb51d25 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -167,9 +167,11 @@ const struct inode_operations ocfs2_symlink_inode_operations = {
.readlink = page_readlink,
.follow_link = ocfs2_follow_link,
.getattr = ocfs2_getattr,
+ .setattr = ocfs2_setattr,
};
const struct inode_operations ocfs2_fast_symlink_inode_operations = {
.readlink = ocfs2_readlink,
.follow_link = ocfs2_follow_link,
.getattr = ocfs2_getattr,
+ .setattr = ocfs2_setattr,
};
diff --git a/fs/open.c b/fs/open.c
index 7af1f05d597..a1450086e92 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -7,6 +7,7 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/quotaops.h>
#include <linux/fsnotify.h>
#include <linux/module.h>
diff --git a/fs/proc/array.c b/fs/proc/array.c
index c135cbdd912..dca997a93bf 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -73,6 +73,7 @@
#include <linux/signal.h>
#include <linux/highmem.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/times.h>
#include <linux/cpuset.h>
#include <linux/rcupdate.h>
diff --git a/fs/proc/base.c b/fs/proc/base.c
index fcf02f2deeb..808cbdc193d 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -56,6 +56,7 @@
#include <linux/init.h>
#include <linux/capability.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/namei.h>
diff --git a/fs/select.c b/fs/select.c
index 2c292146e24..8dda969614a 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -21,6 +21,7 @@
#include <linux/poll.h>
#include <linux/personality.h> /* for STICKY_TIMEOUTS */
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/rcupdate.h>
@@ -298,7 +299,7 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
#define MAX_SELECT_SECONDS \
((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
fd_set __user *exp, s64 *timeout)
{
fd_set_bits fds;
diff --git a/fs/signalfd.c b/fs/signalfd.c
index 8ead0db3593..619725644c7 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -207,11 +207,8 @@ static const struct file_operations signalfd_fops = {
asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask)
{
- int error;
sigset_t sigmask;
struct signalfd_ctx *ctx;
- struct file *file;
- struct inode *inode;
if (sizemask != sizeof(sigset_t) ||
copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
@@ -230,12 +227,11 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
* When we call this, the initialization must be complete, since
* anon_inode_getfd() will install the fd.
*/
- error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]",
- &signalfd_fops, ctx);
- if (error)
- goto err_fdalloc;
+ ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx);
+ if (ufd < 0)
+ kfree(ctx);
} else {
- file = fget(ufd);
+ struct file *file = fget(ufd);
if (!file)
return -EBADF;
ctx = file->private_data;
@@ -252,9 +248,4 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
}
return ufd;
-
-err_fdalloc:
- kfree(ctx);
- return error;
}
-
diff --git a/fs/timerfd.c b/fs/timerfd.c
index 5400524e9cb..d87d354ec42 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -181,10 +181,8 @@ static struct file *timerfd_fget(int fd)
asmlinkage long sys_timerfd_create(int clockid, int flags)
{
- int error, ufd;
+ int ufd;
struct timerfd_ctx *ctx;
- struct file *file;
- struct inode *inode;
if (flags)
return -EINVAL;
@@ -200,12 +198,9 @@ asmlinkage long sys_timerfd_create(int clockid, int flags)
ctx->clockid = clockid;
hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
- error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
- &timerfd_fops, ctx);
- if (error) {
+ ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx);
+ if (ufd < 0)
kfree(ctx);
- return error;
- }
return ufd;
}
diff --git a/fs/utimes.c b/fs/utimes.c
index a2bef77dc9c..af059d5cb48 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -40,9 +40,14 @@ asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times)
#endif
+static bool nsec_special(long nsec)
+{
+ return nsec == UTIME_OMIT || nsec == UTIME_NOW;
+}
+
static bool nsec_valid(long nsec)
{
- if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
+ if (nsec_special(nsec))
return true;
return nsec >= 0 && nsec <= 999999999;
@@ -119,7 +124,15 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
newattrs.ia_valid |= ATTR_MTIME_SET;
}
- } else {
+ }
+
+ /*
+ * If times is NULL or both times are either UTIME_OMIT or
+ * UTIME_NOW, then need to check permissions, because
+ * inode_change_ok() won't do it.
+ */
+ if (!times || (nsec_special(times[0].tv_nsec) &&
+ nsec_special(times[1].tv_nsec))) {
error = -EACCES;
if (IS_IMMUTABLE(inode))
goto mnt_drop_write_and_out;
diff --git a/include/asm-arm/div64.h b/include/asm-arm/div64.h
index 0b5f881c3d8..5001390be95 100644
--- a/include/asm-arm/div64.h
+++ b/include/asm-arm/div64.h
@@ -224,6 +224,4 @@
#endif
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
-
#endif
diff --git a/include/asm-frv/unaligned.h b/include/asm-frv/unaligned.h
index 64ccc736f2d..839a2fbffa0 100644
--- a/include/asm-frv/unaligned.h
+++ b/include/asm-frv/unaligned.h
@@ -9,8 +9,8 @@
* 2 of the License, or (at your option) any later version.
*/
-#ifndef _ASM_FRV_UNALIGNED_H
-#define _ASM_FRV_UNALIGNED_H
+#ifndef _ASM_UNALIGNED_H
+#define _ASM_UNALIGNED_H
#include <linux/unaligned/le_byteshift.h>
#include <linux/unaligned/be_byteshift.h>
@@ -19,4 +19,4 @@
#define get_unaligned __get_unaligned_be
#define put_unaligned __put_unaligned_be
-#endif /* _ASM_FRV_UNALIGNED_H */
+#endif /* _ASM_UNALIGNED_H */
diff --git a/include/asm-generic/div64.h b/include/asm-generic/div64.h
index a4a49370793..8f4e3193342 100644
--- a/include/asm-generic/div64.h
+++ b/include/asm-generic/div64.h
@@ -30,11 +30,6 @@
__rem; \
})
-static inline uint64_t div64_64(uint64_t dividend, uint64_t divisor)
-{
- return dividend / divisor;
-}
-
#elif BITS_PER_LONG == 32
extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
@@ -54,8 +49,6 @@ extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
__rem; \
})
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
-
#else /* BITS_PER_LONG == ?? */
# error do_div() does not yet support the C64
diff --git a/include/asm-ia64/cpu.h b/include/asm-ia64/cpu.h
index e87fa3210a2..fcca30b9f11 100644
--- a/include/asm-ia64/cpu.h
+++ b/include/asm-ia64/cpu.h
@@ -14,8 +14,8 @@ DECLARE_PER_CPU(struct ia64_cpu, cpu_devices);
DECLARE_PER_CPU(int, cpu_state);
-extern int arch_register_cpu(int num);
#ifdef CONFIG_HOTPLUG_CPU
+extern int arch_register_cpu(int num);
extern void arch_unregister_cpu(int);
#endif
diff --git a/include/asm-ia64/dmi.h b/include/asm-ia64/dmi.h
index f3efaa22952..00eb1b130b6 100644
--- a/include/asm-ia64/dmi.h
+++ b/include/asm-ia64/dmi.h
@@ -3,4 +3,9 @@
#include <asm/io.h>
+/* Use normal IO mappings for DMI */
+#define dmi_ioremap ioremap
+#define dmi_iounmap(x,l) iounmap(x)
+#define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
+
#endif
diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
index 4ebed77aa47..260a85ac9d6 100644
--- a/include/asm-ia64/io.h
+++ b/include/asm-ia64/io.h
@@ -423,11 +423,6 @@ extern void __iomem * ioremap(unsigned long offset, unsigned long size);
extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
extern void iounmap (volatile void __iomem *addr);
-/* Use normal IO mappings for DMI */
-#define dmi_ioremap ioremap
-#define dmi_iounmap(x,l) iounmap(x)
-#define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
-
/*
* String version of IO memory access ops:
*/
diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
index f30e0558386..2422ac61658 100644
--- a/include/asm-ia64/thread_info.h
+++ b/include/asm-ia64/thread_info.h
@@ -108,13 +108,11 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk);
#define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */
#define TIF_FREEZE 20 /* is freezing for suspend */
#define TIF_RESTORE_RSE 21 /* user RBS is newer than kernel RBS */
-#define TIF_RESTORE_SIGMASK 22 /* restore signal mask in do_signal() */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
@@ -131,7 +129,18 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk);
#define TIF_WORK_MASK (TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
#define TS_POLLING 1 /* true if in idle loop and not sleeping */
+#define TS_RESTORE_SIGMASK 2 /* restore signal mask in do_signal() */
#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+ struct thread_info *ti = current_thread_info();
+ ti->status |= TS_RESTORE_SIGMASK;
+ set_bit(TIF_SIGPENDING, &ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
+
#endif /* _ASM_IA64_THREAD_INFO_H */
diff --git a/include/asm-m68k/div64.h b/include/asm-m68k/div64.h
index 33caad1628d..8243c931b5c 100644
--- a/include/asm-m68k/div64.h
+++ b/include/asm-m68k/div64.h
@@ -25,5 +25,4 @@
__rem; \
})
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
#endif /* _M68K_DIV64_H */
diff --git a/include/asm-m68knommu/dma.h b/include/asm-m68knommu/dma.h
index 3f20419c633..939a0205621 100644
--- a/include/asm-m68knommu/dma.h
+++ b/include/asm-m68knommu/dma.h
@@ -35,7 +35,8 @@
/*
* Set number of channels of DMA on ColdFire for different implementations.
*/
-#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
+#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) || \
+ defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
#define MAX_M68K_DMA_CHANNELS 4
#elif defined(CONFIG_M5272)
#define MAX_M68K_DMA_CHANNELS 1
diff --git a/include/asm-m68knommu/param.h b/include/asm-m68knommu/param.h
index 96c45101832..6044397adb6 100644
--- a/include/asm-m68knommu/param.h
+++ b/include/asm-m68knommu/param.h
@@ -1,13 +1,16 @@
#ifndef _M68KNOMMU_PARAM_H
#define _M68KNOMMU_PARAM_H
-#define HZ CONFIG_HZ
-
#ifdef __KERNEL__
+#define HZ CONFIG_HZ
#define USER_HZ HZ
#define CLOCKS_PER_SEC (USER_HZ)
#endif
+#ifndef HZ
+#define HZ 100
+#endif
+
#define EXEC_PAGESIZE 4096
#ifndef NOGROUP
diff --git a/include/asm-mips/div64.h b/include/asm-mips/div64.h
index 716371bd098..d1d699105c1 100644
--- a/include/asm-mips/div64.h
+++ b/include/asm-mips/div64.h
@@ -82,7 +82,6 @@
(n) = __quot; \
__mod; })
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
#endif /* (_MIPS_SZLONG == 32) */
#if (_MIPS_SZLONG == 64)
@@ -106,11 +105,6 @@ extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
(n) = __quot; \
__mod; })
-static inline uint64_t div64_64(uint64_t dividend, uint64_t divisor)
-{
- return dividend / divisor;
-}
-
#endif /* (_MIPS_SZLONG == 64) */
#endif /* _ASM_DIV64_H */
diff --git a/include/asm-mn10300/div64.h b/include/asm-mn10300/div64.h
index bf9c515a998..3a8329b3e86 100644
--- a/include/asm-mn10300/div64.h
+++ b/include/asm-mn10300/div64.h
@@ -97,7 +97,4 @@ signed __muldiv64s(signed val, signed mult, signed div)
return result;
}
-extern __attribute__((const))
-uint64_t div64_64(uint64_t dividend, uint64_t divisor);
-
#endif /* _ASM_DIV64 */
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
index 9e8ed6824e1..81ffe3b3c1c 100644
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -178,9 +178,6 @@ enum ps3_cpu_binding {
PS3_BINDING_CPU_1 = 1,
};
-int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
- unsigned int *virq);
-int ps3_virq_destroy(unsigned int virq);
int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
unsigned int *virq);
int ps3_irq_plug_destroy(unsigned int virq);
diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h
index 17ba82ee220..7becc846544 100644
--- a/include/asm-sparc/oplib.h
+++ b/include/asm-sparc/oplib.h
@@ -34,9 +34,6 @@ extern unsigned int prom_rev, prom_prev;
*/
extern int prom_root_node;
-/* PROM stdin and stdout */
-extern int prom_stdin, prom_stdout;
-
/* Pointer to prom structure containing the device tree traversal
* and usage utility functions. Only prom-lib should use these,
* users use the interface defined by the library only!
@@ -84,20 +81,6 @@ extern int prom_devclose(int device_handle);
extern void prom_seek(int device_handle, unsigned int seek_hival,
unsigned int seek_lowval);
-/* Machine memory configuration routine. */
-
-/* This function returns a V0 format memory descriptor table, it has three
- * entries. One for the total amount of physical ram on the machine, one
- * for the amount of physical ram available, and one describing the virtual
- * areas which are allocated by the prom. So, in a sense the physical
- * available is a calculation of the total physical minus the physical mapped
- * by the prom with virtual mappings.
- *
- * These lists are returned pre-sorted, this should make your life easier
- * since the prom itself is way too lazy to do such nice things.
- */
-extern struct linux_mem_v0 *prom_meminfo(void);
-
/* Miscellaneous routines, don't really fit in any category per se. */
/* Reboot the machine with the command line passed. */
diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h
index 39ccf2da297..1625a8c3e0d 100644
--- a/include/asm-sparc/page.h
+++ b/include/asm-sparc/page.h
@@ -38,12 +38,11 @@
/* The following structure is used to hold the physical
* memory configuration of the machine. This is filled in
- * probe_memory() and is later used by mem_init() to set up
- * mem_map[]. We statically allocate SPARC_PHYS_BANKS of
+ * prom_meminit() and is later used by mem_init() to set up
+ * mem_map[]. We statically allocate SPARC_PHYS_BANKS+1 of
* these structs, this is arbitrary. The entry after the
* last valid one has num_bytes==0.
*/
-
struct sparc_phys_banks {
unsigned long base_addr;
unsigned long num_bytes;
diff --git a/include/asm-um/div64.h b/include/asm-um/div64.h
index 7b73b2cd5b3..1e17f7409ca 100644
--- a/include/asm-um/div64.h
+++ b/include/asm-um/div64.h
@@ -3,5 +3,4 @@
#include "asm/arch/div64.h"
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
#endif
diff --git a/include/asm-x86/div64.h b/include/asm-x86/div64.h
index 0dbf8bf3ef0..9a2d644c08e 100644
--- a/include/asm-x86/div64.h
+++ b/include/asm-x86/div64.h
@@ -33,25 +33,25 @@
__mod; \
})
-/*
- * (long)X = ((long long)divs) / (long)div
- * (long)rem = ((long long)divs) % (long)div
- *
- * Warning, this will do an exception if X overflows.
- */
-#define div_long_long_rem(a, b, c) div_ll_X_l_rem(a, b, c)
-
-static inline long div_ll_X_l_rem(long long divs, long div, long *rem)
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
{
- long dum2;
- asm("divl %2":"=a"(dum2), "=d"(*rem)
- : "rm"(div), "A"(divs));
-
- return dum2;
-
+ union {
+ u64 v64;
+ u32 v32[2];
+ } d = { dividend };
+ u32 upper;
+
+ upper = d.v32[1];
+ d.v32[1] = 0;
+ if (upper >= divisor) {
+ d.v32[1] = upper / divisor;
+ upper %= divisor;
+ }
+ asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
+ "rm" (divisor), "0" (d.v32[0]), "1" (upper));
+ return d.v64;
}
-
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
+#define div_u64_rem div_u64_rem
#else
# include <asm-generic/div64.h>
diff --git a/include/asm-x86/dmi.h b/include/asm-x86/dmi.h
index 1241e6ad193..4edf7514a75 100644
--- a/include/asm-x86/dmi.h
+++ b/include/asm-x86/dmi.h
@@ -27,6 +27,7 @@ static inline void *dmi_alloc(unsigned len)
#endif
+/* Use early IO mappings for DMI because it's initialized early */
#define dmi_ioremap early_ioremap
#define dmi_iounmap early_iounmap
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index 6e73467a4fb..049e81e797a 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -133,11 +133,6 @@ extern void *early_ioremap(unsigned long offset, unsigned long size);
extern void early_iounmap(void *addr, unsigned long size);
extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
-/* Use early IO mappings for DMI because it's initialized early */
-#define dmi_ioremap early_ioremap
-#define dmi_iounmap early_iounmap
-#define dmi_alloc alloc_bootmem
-
/*
* ISA I/O bus memory addresses are 1:1 with the physical address.
*/
diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h
index 224658b8d80..833d208c25d 100644
--- a/include/crypto/scatterwalk.h
+++ b/include/crypto/scatterwalk.h
@@ -57,10 +57,14 @@ static inline void scatterwalk_sg_chain(struct scatterlist *sg1, int num,
struct scatterlist *sg2)
{
sg_set_page(&sg1[num - 1], (void *)sg2, 0, 0);
+ sg1[num - 1].page_link &= ~0x02;
}
static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
{
+ if (sg_is_last(sg))
+ return NULL;
+
return (++sg)->length ? sg : (void *)sg_page(sg);
}
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 78fade0a1e3..b7d81b2a904 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -346,6 +346,11 @@ unifdef-y += videodev.h
unifdef-y += virtio_config.h
unifdef-y += virtio_blk.h
unifdef-y += virtio_net.h
+unifdef-y += virtio_9p.h
+unifdef-y += virtio_balloon.h
+unifdef-y += virtio_console.h
+unifdef-y += virtio_pci.h
+unifdef-y += virtio_ring.h
unifdef-y += vt.h
unifdef-y += wait.h
unifdef-y += wanrouter.h
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
index b2e1ba325b9..6129e58ca7c 100644
--- a/include/linux/anon_inodes.h
+++ b/include/linux/anon_inodes.h
@@ -8,8 +8,7 @@
#ifndef _LINUX_ANON_INODES_H
#define _LINUX_ANON_INODES_H
-int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
- const char *name, const struct file_operations *fops,
+int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv);
#endif /* _LINUX_ANON_INODES_H */
diff --git a/include/linux/calc64.h b/include/linux/calc64.h
deleted file mode 100644
index ebf4b8f38d8..00000000000
--- a/include/linux/calc64.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef _LINUX_CALC64_H
-#define _LINUX_CALC64_H
-
-#include <linux/types.h>
-#include <asm/div64.h>
-
-/*
- * This is a generic macro which is used when the architecture
- * specific div64.h does not provide a optimized one.
- *
- * The 64bit dividend is divided by the divisor (data type long), the
- * result is returned and the remainder stored in the variable
- * referenced by remainder (data type long *). In contrast to the
- * do_div macro the dividend is kept intact.
- */
-#ifndef div_long_long_rem
-#define div_long_long_rem(dividend, divisor, remainder) \
- do_div_llr((dividend), divisor, remainder)
-
-static inline unsigned long do_div_llr(const long long dividend,
- const long divisor, long *remainder)
-{
- u64 result = dividend;
-
- *(remainder) = do_div(result, divisor);
- return (unsigned long) result;
-}
-#endif
-
-/*
- * Sign aware variation of the above. On some architectures a
- * negative dividend leads to an divide overflow exception, which
- * is avoided by the sign check.
- */
-static inline long div_long_long_rem_signed(const long long dividend,
- const long divisor, long *remainder)
-{
- long res;
-
- if (unlikely(dividend < 0)) {
- res = -div_long_long_rem(-dividend, divisor, remainder);
- *remainder = -(*remainder);
- } else
- res = div_long_long_rem(dividend, divisor, remainder);
-
- return res;
-}
-
-#endif
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 35094479ca5..55e434feec9 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -93,6 +93,8 @@ struct clocksource {
#endif
};
+extern struct clocksource *clock; /* current clocksource */
+
/*
* Clock source flags bits::
*/
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 8fa7857e153..cf8d11cad5a 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -65,10 +65,11 @@ struct compat_timex {
compat_long_t calcnt;
compat_long_t errcnt;
compat_long_t stbcnt;
+ compat_int_t tai;
compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
- compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
+ compat_int_t :32; compat_int_t :32; compat_int_t :32;
};
#define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW)
diff --git a/include/linux/device.h b/include/linux/device.h
index 832fb0eb293..8c23e3dfe3a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -380,6 +380,12 @@ struct device {
/* Get the wakeup routines, which depend on struct device */
#include <linux/pm_wakeup.h>
+static inline const char *dev_name(struct device *dev)
+{
+ /* will be changed into kobject_name(&dev->kobj) in the near future */
+ return dev->bus_id;
+}
+
#ifdef CONFIG_NUMA
static inline int dev_to_node(struct device *dev)
{
@@ -478,7 +484,7 @@ extern void sysdev_shutdown(void);
extern const char *dev_driver_string(struct device *dev);
#define dev_printk(level, dev, format, arg...) \
printk(level "%s %s: " format , dev_driver_string(dev) , \
- (dev)->bus_id , ## arg)
+ dev_name(dev) , ## arg)
#define dev_emerg(dev, format, arg...) \
dev_printk(KERN_EMERG , dev , format , ## arg)
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
new file mode 100644
index 00000000000..a118f3c0b24
--- /dev/null
+++ b/include/linux/fdtable.h
@@ -0,0 +1,99 @@
+/*
+ * descriptor table internals; you almost certainly want file.h instead.
+ */
+
+#ifndef __LINUX_FDTABLE_H
+#define __LINUX_FDTABLE_H
+
+#include <asm/atomic.h>
+#include <linux/posix_types.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+#include <linux/types.h>
+
+/*
+ * The default fd array needs to be at least BITS_PER_LONG,
+ * as this is the granularity returned by copy_fdset().
+ */
+#define NR_OPEN_DEFAULT BITS_PER_LONG
+
+/*
+ * The embedded_fd_set is a small fd_set,
+ * suitable for most tasks (which open <= BITS_PER_LONG files)
+ */
+struct embedded_fd_set {
+ unsigned long fds_bits[1];
+};
+
+struct fdtable {
+ unsigned int max_fds;
+ struct file ** fd; /* current fd array */
+ fd_set *close_on_exec;
+ fd_set *open_fds;
+ struct rcu_head rcu;
+ struct fdtable *next;
+};
+
+/*
+ * Open file table structure
+ */
+struct files_struct {
+ /*
+ * read mostly part
+ */
+ atomic_t count;
+ struct fdtable *fdt;
+ struct fdtable fdtab;
+ /*
+ * written part on a separate cache line in SMP
+ */
+ spinlock_t file_lock ____cacheline_aligned_in_smp;
+ int next_fd;
+ struct embedded_fd_set close_on_exec_init;
+ struct embedded_fd_set open_fds_init;
+ struct file * fd_array[NR_OPEN_DEFAULT];
+};
+
+#define files_fdtable(files) (rcu_dereference((files)->fdt))
+
+extern struct kmem_cache *filp_cachep;
+
+struct file_operations;
+struct vfsmount;
+struct dentry;
+
+extern int expand_files(struct files_struct *, int nr);
+extern void free_fdtable_rcu(struct rcu_head *rcu);
+extern void __init files_defer_init(void);
+
+static inline void free_fdtable(struct fdtable *fdt)
+{
+ call_rcu(&fdt->rcu, free_fdtable_rcu);
+}
+
+static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
+{
+ struct file * file = NULL;
+ struct fdtable *fdt = files_fdtable(files);
+
+ if (fd < fdt->max_fds)
+ file = rcu_dereference(fdt->fd[fd]);
+ return file;
+}
+
+/*
+ * Check whether the specified fd has an open file.
+ */
+#define fcheck(fd) fcheck_files(current->files, fd)
+
+struct task_struct;
+
+struct files_struct *get_files_struct(struct task_struct *);
+void put_files_struct(struct files_struct *fs);
+void reset_files_struct(struct files_struct *);
+int unshare_files(struct files_struct **);
+
+extern struct kmem_cache *files_cachep;
+
+#endif /* __LINUX_FDTABLE_H */
diff --git a/include/linux/file.h b/include/linux/file.h
index 69baf5a4f0a..27c64bdc68c 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -5,59 +5,11 @@
#ifndef __LINUX_FILE_H
#define __LINUX_FILE_H
-#include <asm/atomic.h>
-#include <linux/posix_types.h>
#include <linux/compiler.h>
-#include <linux/spinlock.h>
-#include <linux/rcupdate.h>
#include <linux/types.h>
+#include <linux/posix_types.h>
-/*
- * The default fd array needs to be at least BITS_PER_LONG,
- * as this is the granularity returned by copy_fdset().
- */
-#define NR_OPEN_DEFAULT BITS_PER_LONG
-
-/*
- * The embedded_fd_set is a small fd_set,
- * suitable for most tasks (which open <= BITS_PER_LONG files)
- */
-struct embedded_fd_set {
- unsigned long fds_bits[1];
-};
-
-struct fdtable {
- unsigned int max_fds;
- struct file ** fd; /* current fd array */
- fd_set *close_on_exec;
- fd_set *open_fds;
- struct rcu_head rcu;
- struct fdtable *next;
-};
-
-/*
- * Open file table structure
- */
-struct files_struct {
- /*
- * read mostly part
- */
- atomic_t count;
- struct fdtable *fdt;
- struct fdtable fdtab;
- /*
- * written part on a separate cache line in SMP
- */
- spinlock_t file_lock ____cacheline_aligned_in_smp;
- int next_fd;
- struct embedded_fd_set close_on_exec_init;
- struct embedded_fd_set open_fds_init;
- struct file * fd_array[NR_OPEN_DEFAULT];
-};
-
-#define files_fdtable(files) (rcu_dereference((files)->fdt))
-
-extern struct kmem_cache *filp_cachep;
+struct file;
extern void __fput(struct file *);
extern void fput(struct file *);
@@ -85,41 +37,7 @@ extern void put_filp(struct file *);
extern int get_unused_fd(void);
extern int get_unused_fd_flags(int flags);
extern void put_unused_fd(unsigned int fd);
-struct kmem_cache;
-
-extern int expand_files(struct files_struct *, int nr);
-extern void free_fdtable_rcu(struct rcu_head *rcu);
-extern void __init files_defer_init(void);
-
-static inline void free_fdtable(struct fdtable *fdt)
-{
- call_rcu(&fdt->rcu, free_fdtable_rcu);
-}
-
-static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
-{
- struct file * file = NULL;
- struct fdtable *fdt = files_fdtable(files);
-
- if (fd < fdt->max_fds)
- file = rcu_dereference(fdt->fd[fd]);
- return file;
-}
-
-/*
- * Check whether the specified fd has an open file.
- */
-#define fcheck(fd) fcheck_files(current->files, fd)
extern void fd_install(unsigned int fd, struct file *file);
-struct task_struct;
-
-struct files_struct *get_files_struct(struct task_struct *);
-void put_files_struct(struct files_struct *fs);
-void reset_files_struct(struct files_struct *);
-int unshare_files(struct files_struct **);
-
-extern struct kmem_cache *files_cachep;
-
#endif /* __LINUX_FILE_H */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index bf6b8a61f8d..b24c2875aa0 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -1,7 +1,7 @@
#ifndef _LINUX__INIT_TASK_H
#define _LINUX__INIT_TASK_H
-#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/rcupdate.h>
#include <linux/irqflags.h>
#include <linux/utsname.h>
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 1883a85625d..552e0ec269c 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -61,6 +61,7 @@ typedef void (*irq_flow_handler_t)(unsigned int irq,
#define IRQ_WAKEUP 0x00100000 /* IRQ triggers system wakeup */
#define IRQ_MOVE_PENDING 0x00200000 /* need to re-target IRQ destination */
#define IRQ_NO_BALANCING 0x00400000 /* IRQ is excluded from balancing */
+#define IRQ_SPURIOUS_DISABLED 0x00800000 /* IRQ was disabled by the spurious trap */
#ifdef CONFIG_IRQ_PER_CPU
# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 33ef710dac2..abb6ac639e8 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -1,7 +1,7 @@
#ifndef _LINUX_JIFFIES_H
#define _LINUX_JIFFIES_H
-#include <linux/calc64.h>
+#include <linux/math64.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/time.h>
diff --git a/include/linux/math64.h b/include/linux/math64.h
new file mode 100644
index 00000000000..c1a5f81501f
--- /dev/null
+++ b/include/linux/math64.h
@@ -0,0 +1,84 @@
+#ifndef _LINUX_MATH64_H
+#define _LINUX_MATH64_H
+
+#include <linux/types.h>
+#include <asm/div64.h>
+
+#if BITS_PER_LONG == 64
+
+/**
+ * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
+ *
+ * This is commonly provided by 32bit archs to provide an optimized 64bit
+ * divide.
+ */
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+ *remainder = dividend % divisor;
+ return dividend / divisor;
+}
+
+/**
+ * div_s64_rem - signed 64bit divide with 32bit divisor with remainder
+ */
+static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
+{
+ *remainder = dividend % divisor;
+ return dividend / divisor;
+}
+
+/**
+ * div64_u64 - unsigned 64bit divide with 64bit divisor
+ */
+static inline u64 div64_u64(u64 dividend, u64 divisor)
+{
+ return dividend / divisor;
+}
+
+#elif BITS_PER_LONG == 32
+
+#ifndef div_u64_rem
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+ *remainder = do_div(dividend, divisor);
+ return dividend;
+}
+#endif
+
+#ifndef div_s64_rem
+extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
+#endif
+
+#ifndef div64_u64
+extern u64 div64_u64(u64 dividend, u64 divisor);
+#endif
+
+#endif /* BITS_PER_LONG */
+
+/**
+ * div_u64 - unsigned 64bit divide with 32bit divisor
+ *
+ * This is the most common 64bit divide and should be used if possible,
+ * as many 32bit archs can optimize this variant better than a full 64bit
+ * divide.
+ */
+#ifndef div_u64
+static inline u64 div_u64(u64 dividend, u32 divisor)
+{
+ u32 remainder;
+ return div_u64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+/**
+ * div_s64 - signed 64bit divide with 32bit divisor
+ */
+#ifndef div_s64
+static inline s64 div_s64(s64 dividend, s32 divisor)
+{
+ s32 remainder;
+ return div_s64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+#endif /* _LINUX_MATH64_H */
diff --git a/include/linux/module.h b/include/linux/module.h
index 819c4e889bf..3e03b1acbc9 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -190,7 +190,7 @@ void *__symbol_get_gpl(const char *symbol);
extern typeof(sym) sym; \
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
- __attribute__((section("__ksymtab_strings"))) \
+ __attribute__((section("__ksymtab_strings"), aligned(1))) \
= MODULE_SYMBOL_PREFIX #sym; \
static const struct kernel_symbol __ksymtab_##sym \
__used \
@@ -229,23 +229,6 @@ enum module_state
MODULE_STATE_GOING,
};
-/* Similar stuff for section attributes. */
-struct module_sect_attr
-{
- struct module_attribute mattr;
- char *name;
- unsigned long address;
-};
-
-struct module_sect_attrs
-{
- struct attribute_group grp;
- int nsections;
- struct module_sect_attr attrs[0];
-};
-
-struct module_param_attrs;
-
struct module
{
enum module_state state;
diff --git a/include/linux/mtd/jedec.h b/include/linux/mtd/jedec.h
deleted file mode 100644
index 9006feb218b..00000000000
--- a/include/linux/mtd/jedec.h
+++ /dev/null
@@ -1,66 +0,0 @@
-
-/* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is
- * commonly use in older AMD chips and is obsolete compared with CFI.
- * It is called JEDEC because the JEDEC association distributes the ID codes
- * for the chips.
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
- * $Id: jedec.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $
- */
-
-#ifndef __LINUX_MTD_JEDEC_H__
-#define __LINUX_MTD_JEDEC_H__
-
-#include <linux/types.h>
-
-#define MAX_JEDEC_CHIPS 16
-
-// Listing of all supported chips and their information
-struct JEDECTable
-{
- __u16 jedec;
- char *name;
- unsigned long size;
- unsigned long sectorsize;
- __u32 capabilities;
-};
-
-// JEDEC being 0 is the end of the chip array
-struct jedec_flash_chip
-{
- __u16 jedec;
- unsigned long size;
- unsigned long sectorsize;
-
- // *(__u8*)(base + (adder << addrshift)) = data << datashift
- // Address size = size << addrshift
- unsigned long base; // Byte 0 of the flash, will be unaligned
- unsigned int datashift; // Useful for 32bit/16bit accesses
- unsigned int addrshift;
- unsigned long offset; // linerized start. base==offset for unbanked, uninterleaved flash
-
- __u32 capabilities;
-
- // These markers are filled in by the flash_chip_scan function
- unsigned long start;
- unsigned long length;
-};
-
-struct jedec_private
-{
- unsigned long size; // Total size of all the devices
-
- /* Bank handling. If sum(bank_fill) == size then this is linear flash.
- Otherwise the mapping has holes in it. bank_fill may be used to
- find the holes, but in the common symetric case
- bank_fill[0] == bank_fill[*], thus addresses may be computed
- mathmatically. bank_fill must be powers of two */
- unsigned is_banked;
- unsigned long bank_fill[MAX_JEDEC_CHIPS];
-
- struct jedec_flash_chip chips[MAX_JEDEC_CHIPS];
-};
-
-#endif
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 0a13bb35f04..245f9098e17 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -143,10 +143,12 @@ struct mtd_info {
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */
- int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
+ /* phys is optional and may be set to NULL */
+ int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys);
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
- void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
+ void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
diff --git a/include/linux/mtd/pmc551.h b/include/linux/mtd/pmc551.h
index a7f6d20ad40..5cc070c24d8 100644
--- a/include/linux/mtd/pmc551.h
+++ b/include/linux/mtd/pmc551.h
@@ -36,8 +36,9 @@ struct mypriv {
* Function Prototypes
*/
static int pmc551_erase(struct mtd_info *, struct erase_info *);
-static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
-static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
+static void pmc551_unpoint(struct mtd_info *, loff_t, size_t);
+static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys);
static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index e5a53daf17f..cf6dbd75939 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1429,6 +1429,7 @@
#define PCI_DEVICE_ID_NEO_2DB9PRI 0x00C9
#define PCI_DEVICE_ID_NEO_2RJ45 0x00CA
#define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB
+#define PCIE_DEVICE_ID_NEO_4_IBM 0x00F4
#define PCI_VENDOR_ID_XIRCOM 0x115d
#define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101
diff --git a/include/linux/poll.h b/include/linux/poll.h
index 16d813b364e..ef453828877 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -117,6 +117,8 @@ void zero_fd_set(unsigned long nr, unsigned long *fdset)
extern int do_select(int n, fd_set_bits *fds, s64 *timeout);
extern int do_sys_poll(struct pollfd __user * ufds, unsigned int nfds,
s64 *timeout);
+extern int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+ fd_set __user *exp, s64 *timeout);
#endif /* KERNEL */
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 52e49dce658..dcddfb20094 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -347,6 +347,9 @@ struct quota_info {
((type) == USRQUOTA ? (sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED) : \
(sb_dqopt(sb)->flags & DQUOT_GRP_SUSPENDED))
+#define sb_any_quota_suspended(sb) (sb_has_quota_suspended(sb, USRQUOTA) | \
+ sb_has_quota_suspended(sb, GRPQUOTA))
+
int register_quota_format(struct quota_format_type *fmt);
void unregister_quota_format(struct quota_format_type *fmt);
diff --git a/include/linux/rio.h b/include/linux/rio.h
index c1c99c9643d..dc0c75556c6 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -161,6 +161,8 @@ enum rio_phy_type {
* @ops: configuration space functions
* @id: Port ID, unique among all ports
* @index: Port index, unique among all port interfaces of the same type
+ * @sys_size: RapidIO common transport system size
+ * @phy_type: RapidIO phy type
* @name: Port name string
* @priv: Master port private data
*/
diff --git a/include/linux/string.h b/include/linux/string.h
index c5d3fcad7b5..efdc44593b5 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -109,5 +109,7 @@ extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
extern void argv_free(char **argv);
+extern bool sysfs_streq(const char *s1, const char *s2);
+
#endif
#endif /* _LINUX_STRING_H_ */
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 7858eac40aa..27bad59dae7 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -196,6 +196,12 @@ static inline int sysfs_update_group(struct kobject *kobj,
return 0;
}
+static inline int sysfs_update_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+ return 0;
+}
+
static inline void sysfs_remove_group(struct kobject *kobj,
const struct attribute_group *grp)
{
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 8ea3e71ba7f..fc6035d29d5 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -58,6 +58,8 @@
#include <asm/param.h>
+#define NTP_API 4 /* NTP API version */
+
/*
* SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
* for a slightly underdamped convergence characteristic. SHIFT_KH
@@ -74,24 +76,22 @@
#define MAXTC 10 /* maximum time constant (shift) */
/*
- * The SHIFT_UPDATE define establishes the decimal point of the
- * time_offset variable which represents the current offset with
- * respect to standard time.
- *
* SHIFT_USEC defines the scaling (shift) of the time_freq and
* time_tolerance variables, which represent the current frequency
* offset and maximum frequency tolerance.
*/
-#define SHIFT_UPDATE (SHIFT_HZ + 1) /* time offset scale (shift) */
#define SHIFT_USEC 16 /* frequency offset scale (shift) */
-#define SHIFT_NSEC 12 /* kernel frequency offset scale */
-
-#define MAXPHASE 512000L /* max phase error (us) */
-#define MAXFREQ (512L << SHIFT_USEC) /* max frequency error (ppm) */
-#define MAXFREQ_NSEC (512000L << SHIFT_NSEC) /* max frequency error (ppb) */
+#define PPM_SCALE (NSEC_PER_USEC << (NTP_SCALE_SHIFT - SHIFT_USEC))
+#define PPM_SCALE_INV_SHIFT 20
+#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \
+ PPM_SCALE + 1)
+
+#define MAXPHASE 500000000l /* max phase error (ns) */
+#define MAXFREQ 500000 /* max frequency error (ns/s) */
+#define MAXFREQ_SCALED ((s64)MAXFREQ << NTP_SCALE_SHIFT)
#define MINSEC 256 /* min interval between updates (s) */
#define MAXSEC 2048 /* max interval between updates (s) */
-#define NTP_PHASE_LIMIT (MAXPHASE << 5) /* beyond max. dispersion */
+#define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5) /* beyond max. dispersion */
/*
* syscall interface - used (mainly by NTP daemon)
@@ -121,9 +121,11 @@ struct timex {
long errcnt; /* calibration errors (ro) */
long stbcnt; /* stability limit exceeded (ro) */
+ int tai; /* TAI offset (ro) */
+
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
- int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32;
};
/*
@@ -135,6 +137,9 @@ struct timex {
#define ADJ_ESTERROR 0x0008 /* estimated time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
+#define ADJ_TAI 0x0080 /* set TAI offset */
+#define ADJ_MICRO 0x1000 /* select microsecond resolution */
+#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
@@ -146,8 +151,6 @@ struct timex {
#define MOD_ESTERROR ADJ_ESTERROR
#define MOD_STATUS ADJ_STATUS
#define MOD_TIMECONST ADJ_TIMECONST
-#define MOD_CLKB ADJ_TICK
-#define MOD_CLKA ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */
/*
@@ -169,9 +172,13 @@ struct timex {
#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
+#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */
+#define STA_MODE 0x4000 /* mode (0 = PLL, 1 = FLL) (ro) */
+#define STA_CLK 0x8000 /* clock source (0 = A, 1 = B) (ro) */
+/* read-only bits */
#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \
- STA_PPSERROR | STA_CLOCKERR) /* read-only bits */
+ STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK)
/*
* Clock states (time_state)
@@ -203,10 +210,9 @@ extern int time_status; /* clock synchronization status bits */
extern long time_maxerror; /* maximum error */
extern long time_esterror; /* estimated error */
-extern long time_freq; /* frequency offset (scaled ppm) */
-
extern long time_adjust; /* The amount of adjtime left */
+extern void ntp_init(void);
extern void ntp_clear(void);
/**
@@ -225,7 +231,7 @@ static inline int ntp_synced(void)
__x < 0 ? -(-__x >> __s) : __x >> __s; \
})
-#define TICK_LENGTH_SHIFT 32
+#define NTP_SCALE_SHIFT 32
#ifdef CONFIG_NO_HZ
#define NTP_INTERVAL_FREQ (2)
@@ -234,8 +240,8 @@ static inline int ntp_synced(void)
#endif
#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
-/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
-extern u64 current_tick_length(void);
+/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
+extern u64 tick_length;
extern void second_overflow(void);
extern void update_ntp_one_tick(void);
diff --git a/include/linux/usb/c67x00.h b/include/linux/usb/c67x00.h
new file mode 100644
index 00000000000..83c6b45470c
--- /dev/null
+++ b/include/linux/usb/c67x00.h
@@ -0,0 +1,48 @@
+/*
+ * usb_c67x00.h: platform definitions for the Cypress C67X00 USB chip
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#ifndef _LINUX_USB_C67X00_H
+#define _LINUX_USB_C67X00_H
+
+/* SIE configuration */
+#define C67X00_SIE_UNUSED 0
+#define C67X00_SIE_HOST 1
+#define C67X00_SIE_PERIPHERAL_A 2 /* peripheral on A port */
+#define C67X00_SIE_PERIPHERAL_B 3 /* peripheral on B port */
+
+#define c67x00_sie_config(config, n) (((config)>>(4*(n)))&0x3)
+
+#define C67X00_SIE1_UNUSED (C67X00_SIE_UNUSED << 0)
+#define C67X00_SIE1_HOST (C67X00_SIE_HOST << 0)
+#define C67X00_SIE1_PERIPHERAL_A (C67X00_SIE_PERIPHERAL_A << 0)
+#define C67X00_SIE1_PERIPHERAL_B (C67X00_SIE_PERIPHERAL_B << 0)
+
+#define C67X00_SIE2_UNUSED (C67X00_SIE_UNUSED << 4)
+#define C67X00_SIE2_HOST (C67X00_SIE_HOST << 4)
+#define C67X00_SIE2_PERIPHERAL_A (C67X00_SIE_PERIPHERAL_A << 4)
+#define C67X00_SIE2_PERIPHERAL_B (C67X00_SIE_PERIPHERAL_B << 4)
+
+struct c67x00_platform_data {
+ int sie_config; /* SIEs config (C67X00_SIEx_*) */
+ unsigned long hpi_regstep; /* Step between HPI registers */
+};
+
+#endif /* _LINUX_USB_C67X00_H */
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 7e0d3084f76..73a2f4eb1f7 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -455,7 +455,7 @@ struct usb_encryption_descriptor {
/*-------------------------------------------------------------------------*/
-/* USB_DT_BOS: group of wireless capabilities */
+/* USB_DT_BOS: group of device-level capabilities */
struct usb_bos_descriptor {
__u8 bLength;
__u8 bDescriptorType;
@@ -501,6 +501,16 @@ struct usb_wireless_cap_descriptor { /* Ultra Wide Band */
__u8 bReserved;
} __attribute__((packed));
+#define USB_CAP_TYPE_EXT 2
+
+struct usb_ext_cap_descriptor { /* Link Power Management */
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDevCapabilityType;
+ __u8 bmAttributes;
+#define USB_LPM_SUPPORT (1 << 1) /* supports LPM */
+} __attribute__((packed));
+
/*-------------------------------------------------------------------------*/
/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index d8128f7102c..cf468fbdbf8 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -114,6 +114,8 @@ struct usb_ep_ops {
int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
int (*set_halt) (struct usb_ep *ep, int value);
+ int (*set_wedge) (struct usb_ep *ep);
+
int (*fifo_status) (struct usb_ep *ep);
void (*fifo_flush) (struct usb_ep *ep);
};
@@ -349,6 +351,25 @@ static inline int usb_ep_clear_halt(struct usb_ep *ep)
}
/**
+ * usb_ep_set_wedge - sets the halt feature and ignores clear requests
+ * @ep: the endpoint being wedged
+ *
+ * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
+ * requests. If the gadget driver clears the halt status, it will
+ * automatically unwedge the endpoint.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_ep_set_wedge(struct usb_ep *ep)
+{
+ if (ep->ops->set_wedge)
+ return ep->ops->set_wedge(ep);
+ else
+ return ep->ops->set_halt(ep, 1);
+}
+
+/**
* usb_ep_fifo_status - returns number of bytes in fifo, or error
* @ep: the endpoint whose fifo status is being checked.
*
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index e7d10845b3c..06005fa9e98 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -76,6 +76,7 @@ struct virtqueue_ops {
* @dev: underlying device.
* @id: the device type identification (used to match it with a driver).
* @config: the configuration ops for this device.
+ * @features: the features supported by both driver and device.
* @priv: private pointer for the driver's use.
*/
struct virtio_device
@@ -84,6 +85,8 @@ struct virtio_device
struct device dev;
struct virtio_device_id id;
struct virtio_config_ops *config;
+ /* Note that this is a Linux set_bit-style bitmap. */
+ unsigned long features[1];
void *priv;
};
@@ -94,6 +97,8 @@ 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.
+ * @feature_table: an array of feature numbers supported by this device.
+ * @feature_table_size: number of entries in the feature table array.
* @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.
@@ -103,6 +108,8 @@ void unregister_virtio_device(struct virtio_device *dev);
struct virtio_driver {
struct device_driver driver;
const struct virtio_device_id *id_table;
+ const unsigned int *feature_table;
+ unsigned int feature_table_size;
int (*probe)(struct virtio_device *dev);
void (*remove)(struct virtio_device *dev);
void (*config_changed)(struct virtio_device *dev);
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
index bca0b10d794..d4695a3356d 100644
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -9,6 +9,7 @@
#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */
#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */
#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
+#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */
struct virtio_blk_config
{
@@ -18,6 +19,12 @@ struct virtio_blk_config
__le32 size_max;
/* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
__le32 seg_max;
+ /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
+ struct virtio_blk_geometry {
+ __le16 cylinders;
+ __u8 heads;
+ __u8 sectors;
+ } geometry;
} __attribute__((packed));
/* These two define direction. */
@@ -41,13 +48,8 @@ struct virtio_blk_outhdr
__u64 sector;
};
+/* And this is the final byte of the write scatter-gather list. */
#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
index d581b2914b3..50db245c81a 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -16,27 +16,20 @@
#define VIRTIO_CONFIG_S_FAILED 0x80
#ifdef __KERNEL__
-struct virtio_device;
+#include <linux/virtio.h>
/**
* virtio_config_ops - operations for configuring a virtio device
- * @feature: search for a feature in this config
- * vdev: the virtio_device
- * bit: the feature bit
- * Returns true if the feature is supported. Acknowledges the feature
- * so the host can see it.
* @get: read the value of a configuration field
* vdev: the virtio_device
* offset: the offset of the configuration field
* buf: the buffer to write the field value into.
* len: the length of the buffer
- * Note that contents are conventionally little-endian.
* @set: write the value of a configuration field
* vdev: the virtio_device
* offset: the offset of the configuration field
* buf: the buffer to read the field value from.
* len: the length of the buffer
- * Note that contents are conventionally little-endian.
* @get_status: read the status byte
* vdev: the virtio_device
* Returns the status byte
@@ -52,10 +45,15 @@ struct virtio_device;
* callback: the virqtueue callback
* Returns the new virtqueue or ERR_PTR() (eg. -ENOENT).
* @del_vq: free a virtqueue found by find_vq().
+ * @get_features: get the array of feature bits for this device.
+ * vdev: the virtio_device
+ * Returns the first 32 feature bits (all we currently need).
+ * @set_features: confirm what device features we'll be using.
+ * vdev: the virtio_device
+ * feature: the first 32 feature bits
*/
struct virtio_config_ops
{
- bool (*feature)(struct virtio_device *vdev, unsigned bit);
void (*get)(struct virtio_device *vdev, unsigned offset,
void *buf, unsigned len);
void (*set)(struct virtio_device *vdev, unsigned offset,
@@ -67,43 +65,52 @@ struct virtio_config_ops
unsigned index,
void (*callback)(struct virtqueue *));
void (*del_vq)(struct virtqueue *vq);
+ u32 (*get_features)(struct virtio_device *vdev);
+ void (*set_features)(struct virtio_device *vdev, u32 features);
};
+/* If driver didn't advertise the feature, it will never appear. */
+void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
+ unsigned int fbit);
+
/**
- * virtio_config_val - look for a feature and get a single virtio config.
- * @vdev: the virtio device
+ * virtio_has_feature - helper to determine if this device has this feature.
+ * @vdev: the device
* @fbit: the feature bit
- * @offset: the type to search for.
- * @val: a pointer to the value to fill in.
- *
- * The return value is -ENOENT if the feature doesn't exist. Otherwise
- * the value is endian-corrected and returned in v. */
-#define virtio_config_val(vdev, fbit, offset, v) ({ \
- int _err; \
- if ((vdev)->config->feature((vdev), (fbit))) { \
- __virtio_config_val((vdev), (offset), (v)); \
- _err = 0; \
- } else \
- _err = -ENOENT; \
- _err; \
-})
+ */
+static inline bool virtio_has_feature(const struct virtio_device *vdev,
+ unsigned int fbit)
+{
+ /* Did you forget to fix assumptions on max features? */
+ if (__builtin_constant_p(fbit))
+ BUILD_BUG_ON(fbit >= 32);
+
+ virtio_check_driver_offered_feature(vdev, fbit);
+ return test_bit(fbit, vdev->features);
+}
/**
- * __virtio_config_val - get a single virtio config without feature check.
+ * virtio_config_val - look for a feature and get a virtio config entry.
* @vdev: the virtio device
+ * @fbit: the feature bit
* @offset: the type to search for.
* @val: a pointer to the value to fill in.
*
- * The value is endian-corrected and returned in v. */
-#define __virtio_config_val(vdev, offset, v) do { \
- BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \
- && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \
- (vdev)->config->get((vdev), (offset), (v), sizeof(*(v))); \
- 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; \
- } \
-} while(0)
+ * The return value is -ENOENT if the feature doesn't exist. Otherwise
+ * the config value is copied into whatever is pointed to by v. */
+#define virtio_config_val(vdev, fbit, offset, v) \
+ virtio_config_buf((vdev), (fbit), (offset), (v), sizeof(v))
+
+static inline int virtio_config_buf(struct virtio_device *vdev,
+ unsigned int fbit,
+ unsigned int offset,
+ void *buf, unsigned len)
+{
+ if (!virtio_has_feature(vdev, fbit))
+ return -ENOENT;
+
+ vdev->config->get(vdev, offset, buf, len);
+ return 0;
+}
#endif /* __KERNEL__ */
#endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 1ea3351df60..9405aa6cdf2 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -6,9 +6,18 @@
#define VIRTIO_ID_NET 1
/* The feature bitmap for virtio net */
-#define VIRTIO_NET_F_CSUM 0 /* Can handle pkts w/ partial csum */
+#define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */
+#define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */
#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */
-#define VIRTIO_NET_F_GSO 6 /* Can handle pkts w/ any GSO type */
+#define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */
+#define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in. */
+#define VIRTIO_NET_F_GUEST_TSO6 8 /* Guest can handle TSOv6 in. */
+#define VIRTIO_NET_F_GUEST_ECN 9 /* Guest can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_GUEST_UFO 10 /* Guest can handle UFO in. */
+#define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in. */
+#define VIRTIO_NET_F_HOST_TSO6 12 /* Host can handle TSOv6 in. */
+#define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */
struct virtio_net_config
{
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 1f74bcd603f..32742c4563d 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -30,13 +30,6 @@
#endif
/*
- * SCSI command lengths
- */
-
-extern const unsigned char scsi_command_size[8];
-#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
-
-/*
* Special value for scanning to specify scanning or rescanning of all
* possible channels, (target) ids, or luns on a given shost.
*/
@@ -109,6 +102,7 @@ extern const unsigned char scsi_command_size[8];
#define MODE_SENSE_10 0x5a
#define PERSISTENT_RESERVE_IN 0x5e
#define PERSISTENT_RESERVE_OUT 0x5f
+#define VARIABLE_LENGTH_CMD 0x7f
#define REPORT_LUNS 0xa0
#define MAINTENANCE_IN 0xa3
#define MOVE_MEDIUM 0xa5
@@ -136,6 +130,38 @@ extern const unsigned char scsi_command_size[8];
#define ATA_12 0xa1 /* 12-byte pass-thru */
/*
+ * SCSI command lengths
+ */
+
+#define SCSI_MAX_VARLEN_CDB_SIZE 260
+
+/* defined in T10 SCSI Primary Commands-2 (SPC2) */
+struct scsi_varlen_cdb_hdr {
+ u8 opcode; /* opcode always == VARIABLE_LENGTH_CMD */
+ u8 control;
+ u8 misc[5];
+ u8 additional_cdb_length; /* total cdb length - 8 */
+ __be16 service_action;
+ /* service specific data follows */
+};
+
+static inline unsigned
+scsi_varlen_cdb_length(const void *hdr)
+{
+ return ((struct scsi_varlen_cdb_hdr *)hdr)->additional_cdb_length + 8;
+}
+
+extern const unsigned char scsi_command_size_tbl[8];
+#define COMMAND_SIZE(opcode) scsi_command_size_tbl[((opcode) >> 5) & 7]
+
+static inline unsigned
+scsi_command_size(const unsigned char *cmnd)
+{
+ return (cmnd[0] == VARIABLE_LENGTH_CMD) ?
+ scsi_varlen_cdb_length(cmnd) : COMMAND_SIZE(cmnd[0]);
+}
+
+/*
* SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
* T10/1561-D Revision 4 Draft dated 7th November 2002.
*/
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 8d20e60a94b..3e46dfae819 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -7,10 +7,28 @@
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/scatterlist.h>
+#include <linux/blkdev.h>
struct Scsi_Host;
struct scsi_device;
+/*
+ * MAX_COMMAND_SIZE is:
+ * The longest fixed-length SCSI CDB as per the SCSI standard.
+ * fixed-length means: commands that their size can be determined
+ * by their opcode and the CDB does not carry a length specifier, (unlike
+ * the VARIABLE_LENGTH_CMD(0x7f) command). This is actually not exactly
+ * true and the SCSI standard also defines extended commands and
+ * vendor specific commands that can be bigger than 16 bytes. The kernel
+ * will support these using the same infrastructure used for VARLEN CDB's.
+ * So in effect MAX_COMMAND_SIZE means the maximum size command scsi-ml
+ * supports without specifying a cmd_len by ULD's
+ */
+#define MAX_COMMAND_SIZE 16
+#if (MAX_COMMAND_SIZE > BLK_MAX_CDB)
+# error MAX_COMMAND_SIZE can not be bigger than BLK_MAX_CDB
+#endif
+
struct scsi_data_buffer {
struct sg_table table;
unsigned length;
@@ -60,12 +78,11 @@ struct scsi_cmnd {
int allowed;
int timeout_per_command;
- unsigned char cmd_len;
+ unsigned short cmd_len;
enum dma_data_direction sc_data_direction;
/* These elements define the operation we are about to perform */
-#define MAX_COMMAND_SIZE 16
- unsigned char cmnd[MAX_COMMAND_SIZE];
+ unsigned char *cmnd;
struct timer_list eh_timeout; /* Used to time out the command. */
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index d3a133b4a07..2a9add21267 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -75,11 +75,11 @@ struct scsi_eh_save {
int result;
enum dma_data_direction data_direction;
unsigned char cmd_len;
- unsigned char cmnd[MAX_COMMAND_SIZE];
+ unsigned char *cmnd;
struct scsi_data_buffer sdb;
struct request *next_rq;
-
/* new command support */
+ unsigned char eh_cmnd[BLK_MAX_CDB];
struct scatterlist sense_sgl;
};
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index d967d6dc7a2..1834fdfe82a 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -573,13 +573,11 @@ struct Scsi_Host {
/*
* The maximum length of SCSI commands that this host can accept.
* Probably 12 for most host adapters, but could be 16 for others.
+ * or 260 if the driver supports variable length cdbs.
* For drivers that don't set this field, a value of 12 is
- * assumed. I am leaving this as a number rather than a bit
- * because you never know what subsequent SCSI standards might do
- * (i.e. could there be a 20 byte or a 24-byte command a few years
- * down the road?).
+ * assumed.
*/
- unsigned char max_cmd_len;
+ unsigned short max_cmd_len;
int this_id;
int can_queue;
diff --git a/kernel/compat.c b/kernel/compat.c
index 4a856a3643b..32c254a8ab9 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -955,7 +955,8 @@ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
__put_user(txc.jitcnt, &utp->jitcnt) ||
__put_user(txc.calcnt, &utp->calcnt) ||
__put_user(txc.errcnt, &utp->errcnt) ||
- __put_user(txc.stbcnt, &utp->stbcnt))
+ __put_user(txc.stbcnt, &utp->stbcnt) ||
+ __put_user(txc.tai, &utp->tai))
ret = -EFAULT;
return ret;
diff --git a/kernel/exit.c b/kernel/exit.c
index d3ad54677f9..1510f78a0ff 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -19,6 +19,7 @@
#include <linux/acct.h>
#include <linux/tsacct_kern.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/binfmts.h>
#include <linux/nsproxy.h>
#include <linux/pid_namespace.h>
diff --git a/kernel/fork.c b/kernel/fork.c
index 2bb675af4de..933e60ebcca 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -22,6 +22,7 @@
#include <linux/mempolicy.h>
#include <linux/sem.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/key.h>
#include <linux/binfmts.h>
#include <linux/mman.h>
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 46e4ad1723f..46d6611a33b 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -150,6 +150,26 @@ void disable_irq(unsigned int irq)
}
EXPORT_SYMBOL(disable_irq);
+static void __enable_irq(struct irq_desc *desc, unsigned int irq)
+{
+ switch (desc->depth) {
+ case 0:
+ printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
+ WARN_ON(1);
+ break;
+ case 1: {
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+
+ /* Prevent probing on this irq: */
+ desc->status = status | IRQ_NOPROBE;
+ check_irq_resend(desc, irq);
+ /* fall-through */
+ }
+ default:
+ desc->depth--;
+ }
+}
+
/**
* enable_irq - enable handling of an irq
* @irq: Interrupt to enable
@@ -169,22 +189,7 @@ void enable_irq(unsigned int irq)
return;
spin_lock_irqsave(&desc->lock, flags);
- switch (desc->depth) {
- case 0:
- printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
- WARN_ON(1);
- break;
- case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
-
- /* Prevent probing on this irq: */
- desc->status = status | IRQ_NOPROBE;
- check_irq_resend(desc, irq);
- /* fall-through */
- }
- default:
- desc->depth--;
- }
+ __enable_irq(desc, irq);
spin_unlock_irqrestore(&desc->lock, flags);
}
EXPORT_SYMBOL(enable_irq);
@@ -365,7 +370,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
compat_irq_chip_set_default_handler(desc);
desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
- IRQ_INPROGRESS);
+ IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
if (!(desc->status & IRQ_NOAUTOEN)) {
desc->depth = 0;
@@ -381,6 +386,16 @@ int setup_irq(unsigned int irq, struct irqaction *new)
/* Reset broken irq detection when installing new handler */
desc->irq_count = 0;
desc->irqs_unhandled = 0;
+
+ /*
+ * Check whether we disabled the irq via the spurious handler
+ * before. Reenable it and give it another chance.
+ */
+ if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
+ desc->status &= ~IRQ_SPURIOUS_DISABLED;
+ __enable_irq(desc, irq);
+ }
+
spin_unlock_irqrestore(&desc->lock, flags);
new->irq = irq;
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 088dabbf2d6..c66d3f10e85 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -209,8 +209,8 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
* Now kill the IRQ
*/
printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
- desc->status |= IRQ_DISABLED;
- desc->depth = 1;
+ desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED;
+ desc->depth++;
desc->chip->disable(irq);
}
desc->irqs_unhandled = 0;
diff --git a/kernel/kexec.c b/kernel/kexec.c
index cb85c79989b..1c5fcacbcf3 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1217,7 +1217,7 @@ static int __init parse_crashkernel_mem(char *cmdline,
}
/* match ? */
- if (system_ram >= start && system_ram <= end) {
+ if (system_ram >= start && system_ram < end) {
*crash_size = size;
break;
}
diff --git a/kernel/kmod.c b/kernel/kmod.c
index e2764047ec0..8df97d3dfda 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -27,6 +27,7 @@
#include <linux/mnt_namespace.h>
#include <linux/completion.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/workqueue.h>
#include <linux/security.h>
#include <linux/mount.h>
diff --git a/kernel/module.c b/kernel/module.c
index 8d6cccc6c3c..8674a390a2e 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -164,131 +164,140 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
return NULL;
}
-static void printk_unused_warning(const char *name)
+static bool always_ok(bool gplok, bool warn, const char *name)
{
- printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
- "however this module is using it.\n", name);
- printk(KERN_WARNING "This symbol will go away in the future.\n");
- printk(KERN_WARNING "Please evalute if this is the right api to use, "
- "and if it really is, submit a report the linux kernel "
- "mailinglist together with submitting your code for "
- "inclusion.\n");
+ return true;
}
-/* Find a symbol, return value, crc and module which owns it */
-static unsigned long __find_symbol(const char *name,
- struct module **owner,
- const unsigned long **crc,
- int gplok)
+static bool printk_unused_warning(bool gplok, bool warn, const char *name)
{
- struct module *mod;
- const struct kernel_symbol *ks;
-
- /* Core kernel first. */
- *owner = NULL;
- ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
- if (ks) {
- *crc = symversion(__start___kcrctab, (ks - __start___ksymtab));
- return ks->value;
+ if (warn) {
+ printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
+ "however this module is using it.\n", name);
+ printk(KERN_WARNING
+ "This symbol will go away in the future.\n");
+ printk(KERN_WARNING
+ "Please evalute if this is the right api to use and if "
+ "it really is, submit a report the linux kernel "
+ "mailinglist together with submitting your code for "
+ "inclusion.\n");
}
- if (gplok) {
- ks = lookup_symbol(name, __start___ksymtab_gpl,
- __stop___ksymtab_gpl);
- if (ks) {
- *crc = symversion(__start___kcrctab_gpl,
- (ks - __start___ksymtab_gpl));
- return ks->value;
- }
- }
- ks = lookup_symbol(name, __start___ksymtab_gpl_future,
- __stop___ksymtab_gpl_future);
- if (ks) {
- if (!gplok) {
- printk(KERN_WARNING "Symbol %s is being used "
- "by a non-GPL module, which will not "
- "be allowed in the future\n", name);
- printk(KERN_WARNING "Please see the file "
- "Documentation/feature-removal-schedule.txt "
- "in the kernel source tree for more "
- "details.\n");
- }
- *crc = symversion(__start___kcrctab_gpl_future,
- (ks - __start___ksymtab_gpl_future));
- return ks->value;
+ return true;
+}
+
+static bool gpl_only_unused_warning(bool gplok, bool warn, const char *name)
+{
+ if (!gplok)
+ return false;
+ return printk_unused_warning(gplok, warn, name);
+}
+
+static bool gpl_only(bool gplok, bool warn, const char *name)
+{
+ return gplok;
+}
+
+static bool warn_if_not_gpl(bool gplok, bool warn, const char *name)
+{
+ if (!gplok && warn) {
+ printk(KERN_WARNING "Symbol %s is being used "
+ "by a non-GPL module, which will not "
+ "be allowed in the future\n", name);
+ printk(KERN_WARNING "Please see the file "
+ "Documentation/feature-removal-schedule.txt "
+ "in the kernel source tree for more details.\n");
}
+ return true;
+}
- ks = lookup_symbol(name, __start___ksymtab_unused,
- __stop___ksymtab_unused);
- if (ks) {
- printk_unused_warning(name);
- *crc = symversion(__start___kcrctab_unused,
- (ks - __start___ksymtab_unused));
- return ks->value;
+struct symsearch {
+ const struct kernel_symbol *start, *stop;
+ const unsigned long *crcs;
+ bool (*check)(bool gplok, bool warn, const char *name);
+};
+
+/* Look through this array of symbol tables for a symbol match which
+ * passes the check function. */
+static const struct kernel_symbol *search_symarrays(const struct symsearch *arr,
+ unsigned int num,
+ const char *name,
+ bool gplok,
+ bool warn,
+ const unsigned long **crc)
+{
+ unsigned int i;
+ const struct kernel_symbol *ks;
+
+ for (i = 0; i < num; i++) {
+ ks = lookup_symbol(name, arr[i].start, arr[i].stop);
+ if (!ks || !arr[i].check(gplok, warn, name))
+ continue;
+
+ if (crc)
+ *crc = symversion(arr[i].crcs, ks - arr[i].start);
+ return ks;
}
+ return NULL;
+}
+
+/* Find a symbol, return value, (optional) crc and (optional) module
+ * which owns it */
+static unsigned long find_symbol(const char *name,
+ struct module **owner,
+ const unsigned long **crc,
+ bool gplok,
+ bool warn)
+{
+ struct module *mod;
+ const struct kernel_symbol *ks;
+ const struct symsearch arr[] = {
+ { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
+ always_ok },
+ { __start___ksymtab_gpl, __stop___ksymtab_gpl,
+ __start___kcrctab_gpl, gpl_only },
+ { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
+ __start___kcrctab_gpl_future, warn_if_not_gpl },
+ { __start___ksymtab_unused, __stop___ksymtab_unused,
+ __start___kcrctab_unused, printk_unused_warning },
+ { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
+ __start___kcrctab_unused_gpl, gpl_only_unused_warning },
+ };
- if (gplok)
- ks = lookup_symbol(name, __start___ksymtab_unused_gpl,
- __stop___ksymtab_unused_gpl);
+ /* Core kernel first. */
+ ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc);
if (ks) {
- printk_unused_warning(name);
- *crc = symversion(__start___kcrctab_unused_gpl,
- (ks - __start___ksymtab_unused_gpl));
+ if (owner)
+ *owner = NULL;
return ks->value;
}
/* Now try modules. */
list_for_each_entry(mod, &modules, list) {
- *owner = mod;
- ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
- if (ks) {
- *crc = symversion(mod->crcs, (ks - mod->syms));
- return ks->value;
- }
-
- if (gplok) {
- ks = lookup_symbol(name, mod->gpl_syms,
- mod->gpl_syms + mod->num_gpl_syms);
- if (ks) {
- *crc = symversion(mod->gpl_crcs,
- (ks - mod->gpl_syms));
- return ks->value;
- }
- }
- ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);
+ struct symsearch arr[] = {
+ { mod->syms, mod->syms + mod->num_syms, mod->crcs,
+ always_ok },
+ { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
+ mod->gpl_crcs, gpl_only },
+ { mod->gpl_future_syms,
+ mod->gpl_future_syms + mod->num_gpl_future_syms,
+ mod->gpl_future_crcs, warn_if_not_gpl },
+ { mod->unused_syms,
+ mod->unused_syms + mod->num_unused_syms,
+ mod->unused_crcs, printk_unused_warning },
+ { mod->unused_gpl_syms,
+ mod->unused_gpl_syms + mod->num_unused_gpl_syms,
+ mod->unused_gpl_crcs, gpl_only_unused_warning },
+ };
+
+ ks = search_symarrays(arr, ARRAY_SIZE(arr),
+ name, gplok, warn, crc);
if (ks) {
- printk_unused_warning(name);
- *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));
- return ks->value;
- }
-
- if (gplok) {
- ks = lookup_symbol(name, mod->unused_gpl_syms,
- mod->unused_gpl_syms + mod->num_unused_gpl_syms);
- if (ks) {
- printk_unused_warning(name);
- *crc = symversion(mod->unused_gpl_crcs,
- (ks - mod->unused_gpl_syms));
- return ks->value;
- }
- }
- ks = lookup_symbol(name, mod->gpl_future_syms,
- (mod->gpl_future_syms +
- mod->num_gpl_future_syms));
- if (ks) {
- if (!gplok) {
- printk(KERN_WARNING "Symbol %s is being used "
- "by a non-GPL module, which will not "
- "be allowed in the future\n", name);
- printk(KERN_WARNING "Please see the file "
- "Documentation/feature-removal-schedule.txt "
- "in the kernel source tree for more "
- "details.\n");
- }
- *crc = symversion(mod->gpl_future_crcs,
- (ks - mod->gpl_future_syms));
+ if (owner)
+ *owner = mod;
return ks->value;
}
}
+
DEBUGP("Failed to find symbol %s\n", name);
return -ENOENT;
}
@@ -736,12 +745,13 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
if (!forced && module_refcount(mod) != 0)
wait_for_zero_refcount(mod);
+ mutex_unlock(&module_mutex);
/* Final destruction now noone is using it. */
- if (mod->exit != NULL) {
- mutex_unlock(&module_mutex);
+ if (mod->exit != NULL)
mod->exit();
- mutex_lock(&module_mutex);
- }
+ blocking_notifier_call_chain(&module_notify_list,
+ MODULE_STATE_GOING, mod);
+ mutex_lock(&module_mutex);
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
free_module(mod);
@@ -777,10 +787,9 @@ static void print_unload_info(struct seq_file *m, struct module *mod)
void __symbol_put(const char *symbol)
{
struct module *owner;
- const unsigned long *crc;
preempt_disable();
- if (IS_ERR_VALUE(__find_symbol(symbol, &owner, &crc, 1)))
+ if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false)))
BUG();
module_put(owner);
preempt_enable();
@@ -924,13 +933,10 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
struct module *mod)
{
const unsigned long *crc;
- struct module *owner;
- if (IS_ERR_VALUE(__find_symbol("struct_module",
- &owner, &crc, 1)))
+ if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false)))
BUG();
- return check_version(sechdrs, versindex, "struct_module", mod,
- crc);
+ return check_version(sechdrs, versindex, "struct_module", mod, crc);
}
/* First part is kernel version, which we ignore. */
@@ -974,8 +980,8 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
unsigned long ret;
const unsigned long *crc;
- ret = __find_symbol(name, &owner, &crc,
- !(mod->taints & TAINT_PROPRIETARY_MODULE));
+ ret = find_symbol(name, &owner, &crc,
+ !(mod->taints & TAINT_PROPRIETARY_MODULE), true);
if (!IS_ERR_VALUE(ret)) {
/* use_module can fail due to OOM,
or module initialization or unloading */
@@ -991,6 +997,20 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
* J. Corbet <corbet@lwn.net>
*/
#if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS)
+struct module_sect_attr
+{
+ struct module_attribute mattr;
+ char *name;
+ unsigned long address;
+};
+
+struct module_sect_attrs
+{
+ struct attribute_group grp;
+ unsigned int nsections;
+ struct module_sect_attr attrs[0];
+};
+
static ssize_t module_sect_show(struct module_attribute *mattr,
struct module *mod, char *buf)
{
@@ -1001,7 +1021,7 @@ static ssize_t module_sect_show(struct module_attribute *mattr,
static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
{
- int section;
+ unsigned int section;
for (section = 0; section < sect_attrs->nsections; section++)
kfree(sect_attrs->attrs[section].name);
@@ -1362,10 +1382,9 @@ void *__symbol_get(const char *symbol)
{
struct module *owner;
unsigned long value;
- const unsigned long *crc;
preempt_disable();
- value = __find_symbol(symbol, &owner, &crc, 1);
+ value = find_symbol(symbol, &owner, NULL, true, true);
if (IS_ERR_VALUE(value))
value = 0;
else if (strong_try_module_get(owner))
@@ -1382,33 +1401,33 @@ EXPORT_SYMBOL_GPL(__symbol_get);
*/
static int verify_export_symbols(struct module *mod)
{
- const char *name = NULL;
- unsigned long i, ret = 0;
+ unsigned int i;
struct module *owner;
- const unsigned long *crc;
-
- for (i = 0; i < mod->num_syms; i++)
- if (!IS_ERR_VALUE(__find_symbol(mod->syms[i].name,
- &owner, &crc, 1))) {
- name = mod->syms[i].name;
- ret = -ENOEXEC;
- goto dup;
- }
+ const struct kernel_symbol *s;
+ struct {
+ const struct kernel_symbol *sym;
+ unsigned int num;
+ } arr[] = {
+ { mod->syms, mod->num_syms },
+ { mod->gpl_syms, mod->num_gpl_syms },
+ { mod->gpl_future_syms, mod->num_gpl_future_syms },
+ { mod->unused_syms, mod->num_unused_syms },
+ { mod->unused_gpl_syms, mod->num_unused_gpl_syms },
+ };
- for (i = 0; i < mod->num_gpl_syms; i++)
- if (!IS_ERR_VALUE(__find_symbol(mod->gpl_syms[i].name,
- &owner, &crc, 1))) {
- name = mod->gpl_syms[i].name;
- ret = -ENOEXEC;
- goto dup;
+ for (i = 0; i < ARRAY_SIZE(arr); i++) {
+ for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
+ if (!IS_ERR_VALUE(find_symbol(s->name, &owner,
+ NULL, true, false))) {
+ printk(KERN_ERR
+ "%s: exports duplicate symbol %s"
+ " (owned by %s)\n",
+ mod->name, s->name, module_name(owner));
+ return -ENOEXEC;
+ }
}
-
-dup:
- if (ret)
- printk(KERN_ERR "%s: exports duplicate symbol %s (owned by %s)\n",
- mod->name, name, module_name(owner));
-
- return ret;
+ }
+ return 0;
}
/* Change all symbols so that st_value encodes the pointer directly. */
@@ -1814,8 +1833,9 @@ static struct module *load_module(void __user *umod,
unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
#endif
- /* Don't keep modinfo section */
+ /* Don't keep modinfo and version sections. */
sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
#ifdef CONFIG_KALLSYMS
/* Keep symbol and string tables for decoding later. */
sechdrs[symindex].sh_flags |= SHF_ALLOC;
@@ -1977,7 +1997,8 @@ static struct module *load_module(void __user *umod,
mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
if (unusedgplcrcindex)
- mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;
+ mod->unused_gpl_crcs
+ = (void *)sechdrs[unusedgplcrcindex].sh_addr;
#ifdef CONFIG_MODVERSIONS
if ((mod->num_syms && !crcindex) ||
@@ -2171,6 +2192,8 @@ sys_init_module(void __user *umod,
mod->state = MODULE_STATE_GOING;
synchronize_sched();
module_put(mod);
+ blocking_notifier_call_chain(&module_notify_list,
+ MODULE_STATE_GOING, mod);
mutex_lock(&module_mutex);
free_module(mod);
mutex_unlock(&module_mutex);
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index ae5c6c147c4..f1525ad06cb 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -4,8 +4,9 @@
#include <linux/sched.h>
#include <linux/posix-timers.h>
-#include <asm/uaccess.h>
#include <linux/errno.h>
+#include <linux/math64.h>
+#include <asm/uaccess.h>
static int check_clock(const clockid_t which_clock)
{
@@ -47,12 +48,10 @@ static void sample_to_timespec(const clockid_t which_clock,
union cpu_time_count cpu,
struct timespec *tp)
{
- if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
- tp->tv_sec = div_long_long_rem(cpu.sched,
- NSEC_PER_SEC, &tp->tv_nsec);
- } else {
+ if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED)
+ *tp = ns_to_timespec(cpu.sched);
+ else
cputime_to_timespec(cpu.cpu, tp);
- }
}
static inline int cpu_time_before(const clockid_t which_clock,
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index dcc199c43a1..6c19e94fd0a 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -534,7 +534,6 @@ struct task_struct *ptrace_get_task_struct(pid_t pid)
#define arch_ptrace_attach(child) do { } while (0)
#endif
-#ifndef __ARCH_SYS_PTRACE
asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
@@ -582,7 +581,6 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
unlock_kernel();
return ret;
}
-#endif /* __ARCH_SYS_PTRACE */
int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data)
{
diff --git a/kernel/sched.c b/kernel/sched.c
index e2f7f5acc80..34bcc5bc120 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -8025,7 +8025,7 @@ static void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
se->my_q = cfs_rq;
se->load.weight = tg->shares;
- se->load.inv_weight = div64_64(1ULL<<32, se->load.weight);
+ se->load.inv_weight = div64_u64(1ULL<<32, se->load.weight);
se->parent = parent;
}
#endif
@@ -8692,7 +8692,7 @@ static void __set_se_shares(struct sched_entity *se, unsigned long shares)
dequeue_entity(cfs_rq, se, 0);
se->load.weight = shares;
- se->load.inv_weight = div64_64((1ULL<<32), shares);
+ se->load.inv_weight = div64_u64((1ULL<<32), shares);
if (on_rq)
enqueue_entity(cfs_rq, se, 0);
@@ -8787,7 +8787,7 @@ static unsigned long to_ratio(u64 period, u64 runtime)
if (runtime == RUNTIME_INF)
return 1ULL << 16;
- return div64_64(runtime << 16, period);
+ return div64_u64(runtime << 16, period);
}
#ifdef CONFIG_CGROUP_SCHED
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index 8a9498e7c83..6b4a12558e8 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -357,8 +357,8 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
avg_per_cpu = p->se.sum_exec_runtime;
if (p->se.nr_migrations) {
- avg_per_cpu = div64_64(avg_per_cpu,
- p->se.nr_migrations);
+ avg_per_cpu = div64_u64(avg_per_cpu,
+ p->se.nr_migrations);
} else {
avg_per_cpu = -1LL;
}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 3c44956ee7e..36e06174004 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -589,16 +589,20 @@ static void takeover_tasklets(unsigned int cpu)
local_irq_disable();
/* Find end, append list for that CPU. */
- *__get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).head;
- __get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).tail;
- per_cpu(tasklet_vec, cpu).head = NULL;
- per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
+ if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) {
+ *(__get_cpu_var(tasklet_vec).tail) = per_cpu(tasklet_vec, cpu).head;
+ __get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).tail;
+ per_cpu(tasklet_vec, cpu).head = NULL;
+ per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
+ }
raise_softirq_irqoff(TASKLET_SOFTIRQ);
- *__get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).head;
- __get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).tail;
- per_cpu(tasklet_hi_vec, cpu).head = NULL;
- per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
+ if (&per_cpu(tasklet_hi_vec, cpu).head != per_cpu(tasklet_hi_vec, cpu).tail) {
+ *__get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).head;
+ __get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).tail;
+ per_cpu(tasklet_hi_vec, cpu).head = NULL;
+ per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
+ }
raise_softirq_irqoff(HI_SOFTIRQ);
local_irq_enable();
diff --git a/kernel/time.c b/kernel/time.c
index 86729042e4c..cbe0d5a222f 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -36,6 +36,7 @@
#include <linux/security.h>
#include <linux/fs.h>
#include <linux/slab.h>
+#include <linux/math64.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -391,13 +392,17 @@ EXPORT_SYMBOL(set_normalized_timespec);
struct timespec ns_to_timespec(const s64 nsec)
{
struct timespec ts;
+ s32 rem;
if (!nsec)
return (struct timespec) {0, 0};
- ts.tv_sec = div_long_long_rem_signed(nsec, NSEC_PER_SEC, &ts.tv_nsec);
- if (unlikely(nsec < 0))
- set_normalized_timespec(&ts, ts.tv_sec, ts.tv_nsec);
+ ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem);
+ if (unlikely(rem < 0)) {
+ ts.tv_sec--;
+ rem += NSEC_PER_SEC;
+ }
+ ts.tv_nsec = rem;
return ts;
}
@@ -527,8 +532,10 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value)
* Convert jiffies to nanoseconds and separate with
* one divide.
*/
- u64 nsec = (u64)jiffies * TICK_NSEC;
- value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_nsec);
+ u32 rem;
+ value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
+ NSEC_PER_SEC, &rem);
+ value->tv_nsec = rem;
}
EXPORT_SYMBOL(jiffies_to_timespec);
@@ -566,12 +573,11 @@ void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value)
* Convert jiffies to nanoseconds and separate with
* one divide.
*/
- u64 nsec = (u64)jiffies * TICK_NSEC;
- long tv_usec;
+ u32 rem;
- value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tv_usec);
- tv_usec /= NSEC_PER_USEC;
- value->tv_usec = tv_usec;
+ value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
+ NSEC_PER_SEC, &rem);
+ value->tv_usec = rem / NSEC_PER_USEC;
}
EXPORT_SYMBOL(jiffies_to_timeval);
@@ -587,9 +593,7 @@ clock_t jiffies_to_clock_t(long x)
return x / (HZ / USER_HZ);
# endif
#else
- u64 tmp = (u64)x * TICK_NSEC;
- do_div(tmp, (NSEC_PER_SEC / USER_HZ));
- return (long)tmp;
+ return div_u64((u64)x * TICK_NSEC, NSEC_PER_SEC / USER_HZ);
#endif
}
EXPORT_SYMBOL(jiffies_to_clock_t);
@@ -601,16 +605,12 @@ unsigned long clock_t_to_jiffies(unsigned long x)
return ~0UL;
return x * (HZ / USER_HZ);
#else
- u64 jif;
-
/* Don't worry about loss of precision here .. */
if (x >= ~0UL / HZ * USER_HZ)
return ~0UL;
/* .. but do try to contain it here */
- jif = x * (u64) HZ;
- do_div(jif, USER_HZ);
- return jif;
+ return div_u64((u64)x * HZ, USER_HZ);
#endif
}
EXPORT_SYMBOL(clock_t_to_jiffies);
@@ -619,10 +619,9 @@ u64 jiffies_64_to_clock_t(u64 x)
{
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
# if HZ < USER_HZ
- x *= USER_HZ;
- do_div(x, HZ);
+ x = div_u64(x * USER_HZ, HZ);
# elif HZ > USER_HZ
- do_div(x, HZ / USER_HZ);
+ x = div_u64(x, HZ / USER_HZ);
# else
/* Nothing to do */
# endif
@@ -632,8 +631,7 @@ u64 jiffies_64_to_clock_t(u64 x)
* but even this doesn't overflow in hundreds of years
* in 64 bits, so..
*/
- x *= TICK_NSEC;
- do_div(x, (NSEC_PER_SEC / USER_HZ));
+ x = div_u64(x * TICK_NSEC, (NSEC_PER_SEC / USER_HZ));
#endif
return x;
}
@@ -642,21 +640,17 @@ EXPORT_SYMBOL(jiffies_64_to_clock_t);
u64 nsec_to_clock_t(u64 x)
{
#if (NSEC_PER_SEC % USER_HZ) == 0
- do_div(x, (NSEC_PER_SEC / USER_HZ));
+ return div_u64(x, NSEC_PER_SEC / USER_HZ);
#elif (USER_HZ % 512) == 0
- x *= USER_HZ/512;
- do_div(x, (NSEC_PER_SEC / 512));
+ return div_u64(x * USER_HZ / 512, NSEC_PER_SEC / 512);
#else
/*
* max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024,
* overflow after 64.99 years.
* exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ...
*/
- x *= 9;
- do_div(x, (unsigned long)((9ull * NSEC_PER_SEC + (USER_HZ/2)) /
- USER_HZ));
+ return div_u64(x * 9, (9ull * NSEC_PER_SEC + (USER_HZ / 2)) / USER_HZ);
#endif
- return x;
}
#if (BITS_PER_LONG < 64)
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 5fd9b946977..5125ddd8196 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -15,7 +15,8 @@
#include <linux/jiffies.h>
#include <linux/hrtimer.h>
#include <linux/capability.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
+#include <linux/clocksource.h>
#include <asm/timex.h>
/*
@@ -23,11 +24,14 @@
*/
unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */
unsigned long tick_nsec; /* ACTHZ period (nsec) */
-static u64 tick_length, tick_length_base;
+u64 tick_length;
+static u64 tick_length_base;
+
+static struct hrtimer leap_timer;
#define MAX_TICKADJ 500 /* microsecs */
#define MAX_TICKADJ_SCALED (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \
- TICK_LENGTH_SHIFT) / NTP_INTERVAL_FREQ)
+ NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
/*
* phase-lock loop variables
@@ -35,11 +39,12 @@ static u64 tick_length, tick_length_base;
/* TIME_ERROR prevents overwriting the CMOS clock */
static int time_state = TIME_OK; /* clock synchronization status */
int time_status = STA_UNSYNC; /* clock status bits */
-static s64 time_offset; /* time adjustment (ns) */
+static long time_tai; /* TAI offset (s) */
+static s64 time_offset; /* time adjustment (ns) */
static long time_constant = 2; /* pll time constant */
long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */
long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */
-long time_freq; /* frequency offset (scaled ppm)*/
+static s64 time_freq; /* frequency offset (scaled ns/s)*/
static long time_reftime; /* time at last adjustment (s) */
long time_adjust;
static long ntp_tick_adj;
@@ -47,16 +52,56 @@ static long ntp_tick_adj;
static void ntp_update_frequency(void)
{
u64 second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ)
- << TICK_LENGTH_SHIFT;
- second_length += (s64)ntp_tick_adj << TICK_LENGTH_SHIFT;
- second_length += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC);
+ << NTP_SCALE_SHIFT;
+ second_length += (s64)ntp_tick_adj << NTP_SCALE_SHIFT;
+ second_length += time_freq;
tick_length_base = second_length;
- do_div(second_length, HZ);
- tick_nsec = second_length >> TICK_LENGTH_SHIFT;
+ tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
+ tick_length_base = div_u64(tick_length_base, NTP_INTERVAL_FREQ);
+}
+
+static void ntp_update_offset(long offset)
+{
+ long mtemp;
+ s64 freq_adj;
+
+ if (!(time_status & STA_PLL))
+ return;
- do_div(tick_length_base, NTP_INTERVAL_FREQ);
+ if (!(time_status & STA_NANO))
+ offset *= NSEC_PER_USEC;
+
+ /*
+ * Scale the phase adjustment and
+ * clamp to the operating range.
+ */
+ offset = min(offset, MAXPHASE);
+ offset = max(offset, -MAXPHASE);
+
+ /*
+ * Select how the frequency is to be controlled
+ * and in which mode (PLL or FLL).
+ */
+ if (time_status & STA_FREQHOLD || time_reftime == 0)
+ time_reftime = xtime.tv_sec;
+ mtemp = xtime.tv_sec - time_reftime;
+ time_reftime = xtime.tv_sec;
+
+ freq_adj = (s64)offset * mtemp;
+ freq_adj <<= NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant);
+ time_status &= ~STA_MODE;
+ if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
+ freq_adj += div_s64((s64)offset << (NTP_SCALE_SHIFT - SHIFT_FLL),
+ mtemp);
+ time_status |= STA_MODE;
+ }
+ freq_adj += time_freq;
+ freq_adj = min(freq_adj, MAXFREQ_SCALED);
+ time_freq = max(freq_adj, -MAXFREQ_SCALED);
+
+ time_offset = div_s64((s64)offset << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);
}
/**
@@ -78,62 +123,70 @@ void ntp_clear(void)
}
/*
- * this routine handles the overflow of the microsecond field
- *
- * The tricky bits of code to handle the accurate clock support
- * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
- * They were originally developed for SUN and DEC kernels.
- * All the kudos should go to Dave for this stuff.
+ * Leap second processing. If in leap-insert state at the end of the
+ * day, the system clock is set back one second; if in leap-delete
+ * state, the system clock is set ahead one second.
*/
-void second_overflow(void)
+static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)
{
- long time_adj;
+ enum hrtimer_restart res = HRTIMER_NORESTART;
- /* Bump the maxerror field */
- time_maxerror += MAXFREQ >> SHIFT_USEC;
- if (time_maxerror > NTP_PHASE_LIMIT) {
- time_maxerror = NTP_PHASE_LIMIT;
- time_status |= STA_UNSYNC;
- }
+ write_seqlock_irq(&xtime_lock);
- /*
- * Leap second processing. If in leap-insert state at the end of the
- * day, the system clock is set back one second; if in leap-delete
- * state, the system clock is set ahead one second. The microtime()
- * routine or external clock driver will insure that reported time is
- * always monotonic. The ugly divides should be replaced.
- */
switch (time_state) {
case TIME_OK:
- if (time_status & STA_INS)
- time_state = TIME_INS;
- else if (time_status & STA_DEL)
- time_state = TIME_DEL;
break;
case TIME_INS:
- if (xtime.tv_sec % 86400 == 0) {
- xtime.tv_sec--;
- wall_to_monotonic.tv_sec++;
- time_state = TIME_OOP;
- printk(KERN_NOTICE "Clock: inserting leap second "
- "23:59:60 UTC\n");
- }
+ xtime.tv_sec--;
+ wall_to_monotonic.tv_sec++;
+ time_state = TIME_OOP;
+ printk(KERN_NOTICE "Clock: "
+ "inserting leap second 23:59:60 UTC\n");
+ leap_timer.expires = ktime_add_ns(leap_timer.expires,
+ NSEC_PER_SEC);
+ res = HRTIMER_RESTART;
break;
case TIME_DEL:
- if ((xtime.tv_sec + 1) % 86400 == 0) {
- xtime.tv_sec++;
- wall_to_monotonic.tv_sec--;
- time_state = TIME_WAIT;
- printk(KERN_NOTICE "Clock: deleting leap second "
- "23:59:59 UTC\n");
- }
+ xtime.tv_sec++;
+ time_tai--;
+ wall_to_monotonic.tv_sec--;
+ time_state = TIME_WAIT;
+ printk(KERN_NOTICE "Clock: "
+ "deleting leap second 23:59:59 UTC\n");
break;
case TIME_OOP:
+ time_tai++;
time_state = TIME_WAIT;
- break;
+ /* fall through */
case TIME_WAIT:
if (!(time_status & (STA_INS | STA_DEL)))
- time_state = TIME_OK;
+ time_state = TIME_OK;
+ break;
+ }
+ update_vsyscall(&xtime, clock);
+
+ write_sequnlock_irq(&xtime_lock);
+
+ return res;
+}
+
+/*
+ * this routine handles the overflow of the microsecond field
+ *
+ * The tricky bits of code to handle the accurate clock support
+ * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
+ * They were originally developed for SUN and DEC kernels.
+ * All the kudos should go to Dave for this stuff.
+ */
+void second_overflow(void)
+{
+ s64 time_adj;
+
+ /* Bump the maxerror field */
+ time_maxerror += MAXFREQ / NSEC_PER_USEC;
+ if (time_maxerror > NTP_PHASE_LIMIT) {
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_status |= STA_UNSYNC;
}
/*
@@ -143,7 +196,7 @@ void second_overflow(void)
tick_length = tick_length_base;
time_adj = shift_right(time_offset, SHIFT_PLL + time_constant);
time_offset -= time_adj;
- tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE);
+ tick_length += time_adj;
if (unlikely(time_adjust)) {
if (time_adjust > MAX_TICKADJ) {
@@ -154,25 +207,12 @@ void second_overflow(void)
tick_length -= MAX_TICKADJ_SCALED;
} else {
tick_length += (s64)(time_adjust * NSEC_PER_USEC /
- NTP_INTERVAL_FREQ) << TICK_LENGTH_SHIFT;
+ NTP_INTERVAL_FREQ) << NTP_SCALE_SHIFT;
time_adjust = 0;
}
}
}
-/*
- * Return how long ticks are at the moment, that is, how much time
- * update_wall_time_one_tick will add to xtime next time we call it
- * (assuming no calls to do_adjtimex in the meantime).
- * The return value is in fixed-point nanoseconds shifted by the
- * specified number of bits to the right of the binary point.
- * This function has no side-effects.
- */
-u64 current_tick_length(void)
-{
- return tick_length;
-}
-
#ifdef CONFIG_GENERIC_CMOS_UPDATE
/* Disable the cmos update - used by virtualization and embedded */
@@ -236,8 +276,8 @@ static inline void notify_cmos_timer(void) { }
*/
int do_adjtimex(struct timex *txc)
{
- long mtemp, save_adjust, rem;
- s64 freq_adj, temp64;
+ struct timespec ts;
+ long save_adjust, sec;
int result;
/* In order to modify anything, you gotta be super-user! */
@@ -247,147 +287,132 @@ int do_adjtimex(struct timex *txc)
/* Now we validate the data before disabling interrupts */
if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) {
- /* singleshot must not be used with any other mode bits */
- if (txc->modes != ADJ_OFFSET_SINGLESHOT &&
- txc->modes != ADJ_OFFSET_SS_READ)
+ /* singleshot must not be used with any other mode bits */
+ if (txc->modes & ~ADJ_OFFSET_SS_READ)
return -EINVAL;
}
- if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
- /* adjustment Offset limited to +- .512 seconds */
- if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
- return -EINVAL;
-
/* if the quartz is off by more than 10% something is VERY wrong ! */
if (txc->modes & ADJ_TICK)
if (txc->tick < 900000/USER_HZ ||
txc->tick > 1100000/USER_HZ)
return -EINVAL;
+ if (time_state != TIME_OK && txc->modes & ADJ_STATUS)
+ hrtimer_cancel(&leap_timer);
+ getnstimeofday(&ts);
+
write_seqlock_irq(&xtime_lock);
- result = time_state; /* mostly `TIME_OK' */
/* Save for later - semantics of adjtime is to return old value */
save_adjust = time_adjust;
-#if 0 /* STA_CLOCKERR is never set yet */
- time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */
-#endif
/* If there are input parameters, then process them */
- if (txc->modes)
- {
- if (txc->modes & ADJ_STATUS) /* only set allowed bits */
- time_status = (txc->status & ~STA_RONLY) |
- (time_status & STA_RONLY);
-
- if (txc->modes & ADJ_FREQUENCY) { /* p. 22 */
- if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
- result = -EINVAL;
- goto leave;
- }
- time_freq = ((s64)txc->freq * NSEC_PER_USEC)
- >> (SHIFT_USEC - SHIFT_NSEC);
- }
-
- if (txc->modes & ADJ_MAXERROR) {
- if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
- result = -EINVAL;
- goto leave;
+ if (txc->modes) {
+ if (txc->modes & ADJ_STATUS) {
+ if ((time_status & STA_PLL) &&
+ !(txc->status & STA_PLL)) {
+ time_state = TIME_OK;
+ time_status = STA_UNSYNC;
+ }
+ /* only set allowed bits */
+ time_status &= STA_RONLY;
+ time_status |= txc->status & ~STA_RONLY;
+
+ switch (time_state) {
+ case TIME_OK:
+ start_timer:
+ sec = ts.tv_sec;
+ if (time_status & STA_INS) {
+ time_state = TIME_INS;
+ sec += 86400 - sec % 86400;
+ hrtimer_start(&leap_timer, ktime_set(sec, 0), HRTIMER_MODE_ABS);
+ } else if (time_status & STA_DEL) {
+ time_state = TIME_DEL;
+ sec += 86400 - (sec + 1) % 86400;
+ hrtimer_start(&leap_timer, ktime_set(sec, 0), HRTIMER_MODE_ABS);
+ }
+ break;
+ case TIME_INS:
+ case TIME_DEL:
+ time_state = TIME_OK;
+ goto start_timer;
+ break;
+ case TIME_WAIT:
+ if (!(time_status & (STA_INS | STA_DEL)))
+ time_state = TIME_OK;
+ break;
+ case TIME_OOP:
+ hrtimer_restart(&leap_timer);
+ break;
+ }
}
- time_maxerror = txc->maxerror;
- }
- if (txc->modes & ADJ_ESTERROR) {
- if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
- result = -EINVAL;
- goto leave;
+ if (txc->modes & ADJ_NANO)
+ time_status |= STA_NANO;
+ if (txc->modes & ADJ_MICRO)
+ time_status &= ~STA_NANO;
+
+ if (txc->modes & ADJ_FREQUENCY) {
+ time_freq = (s64)txc->freq * PPM_SCALE;
+ time_freq = min(time_freq, MAXFREQ_SCALED);
+ time_freq = max(time_freq, -MAXFREQ_SCALED);
}
- time_esterror = txc->esterror;
- }
- if (txc->modes & ADJ_TIMECONST) { /* p. 24 */
- if (txc->constant < 0) { /* NTP v4 uses values > 6 */
- result = -EINVAL;
- goto leave;
+ if (txc->modes & ADJ_MAXERROR)
+ time_maxerror = txc->maxerror;
+ if (txc->modes & ADJ_ESTERROR)
+ time_esterror = txc->esterror;
+
+ if (txc->modes & ADJ_TIMECONST) {
+ time_constant = txc->constant;
+ if (!(time_status & STA_NANO))
+ time_constant += 4;
+ time_constant = min(time_constant, (long)MAXTC);
+ time_constant = max(time_constant, 0l);
}
- time_constant = min(txc->constant + 4, (long)MAXTC);
- }
- if (txc->modes & ADJ_OFFSET) { /* values checked earlier */
- if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
- /* adjtime() is independent from ntp_adjtime() */
- time_adjust = txc->offset;
+ if (txc->modes & ADJ_TAI && txc->constant > 0)
+ time_tai = txc->constant;
+
+ if (txc->modes & ADJ_OFFSET) {
+ if (txc->modes == ADJ_OFFSET_SINGLESHOT)
+ /* adjtime() is independent from ntp_adjtime() */
+ time_adjust = txc->offset;
+ else
+ ntp_update_offset(txc->offset);
}
- else if (time_status & STA_PLL) {
- time_offset = txc->offset * NSEC_PER_USEC;
-
- /*
- * Scale the phase adjustment and
- * clamp to the operating range.
- */
- time_offset = min(time_offset, (s64)MAXPHASE * NSEC_PER_USEC);
- time_offset = max(time_offset, (s64)-MAXPHASE * NSEC_PER_USEC);
-
- /*
- * Select whether the frequency is to be controlled
- * and in which mode (PLL or FLL). Clamp to the operating
- * range. Ugly multiply/divide should be replaced someday.
- */
-
- if (time_status & STA_FREQHOLD || time_reftime == 0)
- time_reftime = xtime.tv_sec;
- mtemp = xtime.tv_sec - time_reftime;
- time_reftime = xtime.tv_sec;
-
- freq_adj = time_offset * mtemp;
- freq_adj = shift_right(freq_adj, time_constant * 2 +
- (SHIFT_PLL + 2) * 2 - SHIFT_NSEC);
- if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
- u64 utemp64;
- temp64 = time_offset << (SHIFT_NSEC - SHIFT_FLL);
- if (time_offset < 0) {
- utemp64 = -temp64;
- do_div(utemp64, mtemp);
- freq_adj -= utemp64;
- } else {
- utemp64 = temp64;
- do_div(utemp64, mtemp);
- freq_adj += utemp64;
- }
- }
- freq_adj += time_freq;
- freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC);
- time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC);
- time_offset = div_long_long_rem_signed(time_offset,
- NTP_INTERVAL_FREQ,
- &rem);
- time_offset <<= SHIFT_UPDATE;
- } /* STA_PLL */
- } /* txc->modes & ADJ_OFFSET */
- if (txc->modes & ADJ_TICK)
- tick_usec = txc->tick;
-
- if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
- ntp_update_frequency();
- } /* txc->modes */
-leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
+ if (txc->modes & ADJ_TICK)
+ tick_usec = txc->tick;
+
+ if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
+ ntp_update_frequency();
+ }
+
+ result = time_state; /* mostly `TIME_OK' */
+ if (time_status & (STA_UNSYNC|STA_CLOCKERR))
result = TIME_ERROR;
if ((txc->modes == ADJ_OFFSET_SINGLESHOT) ||
- (txc->modes == ADJ_OFFSET_SS_READ))
+ (txc->modes == ADJ_OFFSET_SS_READ))
txc->offset = save_adjust;
- else
- txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) *
- NTP_INTERVAL_FREQ / 1000;
- txc->freq = (time_freq / NSEC_PER_USEC) <<
- (SHIFT_USEC - SHIFT_NSEC);
+ else {
+ txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
+ NTP_SCALE_SHIFT);
+ if (!(time_status & STA_NANO))
+ txc->offset /= NSEC_PER_USEC;
+ }
+ txc->freq = shift_right((s32)(time_freq >> PPM_SCALE_INV_SHIFT) *
+ (s64)PPM_SCALE_INV,
+ NTP_SCALE_SHIFT);
txc->maxerror = time_maxerror;
txc->esterror = time_esterror;
txc->status = time_status;
txc->constant = time_constant;
txc->precision = 1;
- txc->tolerance = MAXFREQ;
+ txc->tolerance = MAXFREQ_SCALED / PPM_SCALE;
txc->tick = tick_usec;
+ txc->tai = time_tai;
/* PPS is not implemented, so these are zero */
txc->ppsfreq = 0;
@@ -399,9 +424,15 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
txc->errcnt = 0;
txc->stbcnt = 0;
write_sequnlock_irq(&xtime_lock);
- do_gettimeofday(&txc->time);
+
+ txc->time.tv_sec = ts.tv_sec;
+ txc->time.tv_usec = ts.tv_nsec;
+ if (!(time_status & STA_NANO))
+ txc->time.tv_usec /= NSEC_PER_USEC;
+
notify_cmos_timer();
- return(result);
+
+ return result;
}
static int __init ntp_tick_adj_setup(char *str)
@@ -411,3 +442,10 @@ static int __init ntp_tick_adj_setup(char *str)
}
__setup("ntp_tick_adj=", ntp_tick_adj_setup);
+
+void __init ntp_init(void)
+{
+ ntp_clear();
+ hrtimer_init(&leap_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ leap_timer.function = ntp_leap_second;
+}
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 2d6087c7cf9..e91c29f961c 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -53,7 +53,7 @@ void update_xtime_cache(u64 nsec)
timespec_add_ns(&xtime_cache, nsec);
}
-static struct clocksource *clock; /* pointer to current clocksource */
+struct clocksource *clock;
#ifdef CONFIG_GENERIC_TIME
@@ -246,7 +246,7 @@ void __init timekeeping_init(void)
write_seqlock_irqsave(&xtime_lock, flags);
- ntp_clear();
+ ntp_init();
clock = clocksource_get_next();
clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
@@ -371,7 +371,7 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
* here. This is tuned so that an error of about 1 msec is adjusted
* within about 1 sec (or 2^20 nsec in 2^SHIFT_HZ ticks).
*/
- error2 = clock->error >> (TICK_LENGTH_SHIFT + 22 - 2 * SHIFT_HZ);
+ error2 = clock->error >> (NTP_SCALE_SHIFT + 22 - 2 * SHIFT_HZ);
error2 = abs(error2);
for (look_ahead = 0; error2 > 0; look_ahead++)
error2 >>= 2;
@@ -380,8 +380,7 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
* Now calculate the error in (1 << look_ahead) ticks, but first
* remove the single look ahead already included in the error.
*/
- tick_error = current_tick_length() >>
- (TICK_LENGTH_SHIFT - clock->shift + 1);
+ tick_error = tick_length >> (NTP_SCALE_SHIFT - clock->shift + 1);
tick_error -= clock->xtime_interval >> 1;
error = ((error - tick_error) >> look_ahead) + tick_error;
@@ -412,7 +411,7 @@ static void clocksource_adjust(s64 offset)
s64 error, interval = clock->cycle_interval;
int adj;
- error = clock->error >> (TICK_LENGTH_SHIFT - clock->shift - 1);
+ error = clock->error >> (NTP_SCALE_SHIFT - clock->shift - 1);
if (error > interval) {
error >>= 2;
if (likely(error <= interval))
@@ -434,7 +433,7 @@ static void clocksource_adjust(s64 offset)
clock->xtime_interval += interval;
clock->xtime_nsec -= offset;
clock->error -= (interval - offset) <<
- (TICK_LENGTH_SHIFT - clock->shift);
+ (NTP_SCALE_SHIFT - clock->shift);
}
/**
@@ -473,8 +472,8 @@ void update_wall_time(void)
}
/* accumulate error between NTP and clock interval */
- clock->error += current_tick_length();
- clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
+ clock->error += tick_length;
+ clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift);
}
/* correct the clock when NTP error is too big */
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 721093a2256..29fc39f1029 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -195,7 +195,6 @@ static void delayed_work_timer_fn(unsigned long __data)
int queue_delayed_work(struct workqueue_struct *wq,
struct delayed_work *dwork, unsigned long delay)
{
- timer_stats_timer_set_start_info(&dwork->timer);
if (delay == 0)
return queue_work(wq, &dwork->work);
@@ -219,11 +218,12 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct timer_list *timer = &dwork->timer;
struct work_struct *work = &dwork->work;
- timer_stats_timer_set_start_info(&dwork->timer);
if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
BUG_ON(timer_pending(timer));
BUG_ON(!list_empty(&work->entry));
+ timer_stats_timer_set_start_info(&dwork->timer);
+
/* This stores cwq for the moment, for the timer_fn */
set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id()));
timer->expires = jiffies + delay;
@@ -564,7 +564,6 @@ EXPORT_SYMBOL(schedule_work);
int schedule_delayed_work(struct delayed_work *dwork,
unsigned long delay)
{
- timer_stats_timer_set_start_info(&dwork->timer);
return queue_delayed_work(keventd_wq, dwork, delay);
}
EXPORT_SYMBOL(schedule_delayed_work);
@@ -581,7 +580,6 @@ EXPORT_SYMBOL(schedule_delayed_work);
int schedule_delayed_work_on(int cpu,
struct delayed_work *dwork, unsigned long delay)
{
- timer_stats_timer_set_start_info(&dwork->timer);
return queue_delayed_work_on(cpu, keventd_wq, dwork, delay);
}
EXPORT_SYMBOL(schedule_delayed_work_on);
diff --git a/lib/div64.c b/lib/div64.c
index b71cf93c529..bb5bd0c0f03 100644
--- a/lib/div64.c
+++ b/lib/div64.c
@@ -16,9 +16,8 @@
* assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
*/
-#include <linux/types.h>
#include <linux/module.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
/* Not needed on 64bit architectures */
#if BITS_PER_LONG == 32
@@ -58,10 +57,31 @@ uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
EXPORT_SYMBOL(__div64_32);
+#ifndef div_s64_rem
+s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
+{
+ u64 quotient;
+
+ if (dividend < 0) {
+ quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
+ *remainder = -*remainder;
+ if (divisor > 0)
+ quotient = -quotient;
+ } else {
+ quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
+ if (divisor < 0)
+ quotient = -quotient;
+ }
+ return quotient;
+}
+EXPORT_SYMBOL(div_s64_rem);
+#endif
+
/* 64bit divisor, dividend and result. dynamic precision */
-uint64_t div64_64(uint64_t dividend, uint64_t divisor)
+#ifndef div64_u64
+u64 div64_u64(u64 dividend, u64 divisor)
{
- uint32_t high, d;
+ u32 high, d;
high = divisor >> 32;
if (high) {
@@ -72,10 +92,9 @@ uint64_t div64_64(uint64_t dividend, uint64_t divisor)
} else
d = divisor;
- do_div(dividend, d);
-
- return dividend;
+ return div_u64(dividend, d);
}
-EXPORT_SYMBOL(div64_64);
+EXPORT_SYMBOL(div64_u64);
+#endif
#endif /* BITS_PER_LONG == 32 */
diff --git a/lib/idr.c b/lib/idr.c
index 8368c81fcb7..7a02e173f02 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -385,8 +385,8 @@ void idr_remove(struct idr *idp, int id)
while (idp->id_free_cnt >= IDR_FREE_MAX) {
p = alloc_layer(idp);
kmem_cache_free(idr_layer_cache, p);
- return;
}
+ return;
}
EXPORT_SYMBOL(idr_remove);
diff --git a/lib/string.c b/lib/string.c
index 5efafed3d6b..b19b87af65a 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -493,6 +493,33 @@ char *strsep(char **s, const char *ct)
EXPORT_SYMBOL(strsep);
#endif
+/**
+ * sysfs_streq - return true if strings are equal, modulo trailing newline
+ * @s1: one string
+ * @s2: another string
+ *
+ * This routine returns true iff two strings are equal, treating both
+ * NUL and newline-then-NUL as equivalent string terminations. It's
+ * geared for use with sysfs input strings, which generally terminate
+ * with newlines but are compared against values without newlines.
+ */
+bool sysfs_streq(const char *s1, const char *s2)
+{
+ while (*s1 && *s1 == *s2) {
+ s1++;
+ s2++;
+ }
+
+ if (*s1 == *s2)
+ return true;
+ if (!*s1 && *s2 == '\n' && !s2[1])
+ return true;
+ if (*s1 == '\n' && !s1[1] && !*s2)
+ return true;
+ return false;
+}
+EXPORT_SYMBOL(sysfs_streq);
+
#ifndef __HAVE_ARCH_MEMSET
/**
* memset - Fill a region of memory with the given value
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 33add96cd5f..e46451e1d9b 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -48,6 +48,8 @@ enum mem_cgroup_stat_index {
*/
MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */
MEM_CGROUP_STAT_RSS, /* # of pages charged as rss */
+ MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */
+ MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */
MEM_CGROUP_STAT_NSTATS,
};
@@ -199,6 +201,13 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *mem, int flags,
__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_CACHE, val);
else
__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_RSS, val);
+
+ if (charge)
+ __mem_cgroup_stat_add_safe(stat,
+ MEM_CGROUP_STAT_PGPGIN_COUNT, 1);
+ else
+ __mem_cgroup_stat_add_safe(stat,
+ MEM_CGROUP_STAT_PGPGOUT_COUNT, 1);
}
static struct mem_cgroup_per_zone *
@@ -884,6 +893,8 @@ static const struct mem_cgroup_stat_desc {
} mem_cgroup_stat_desc[] = {
[MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, },
[MEM_CGROUP_STAT_RSS] = { "rss", PAGE_SIZE, },
+ [MEM_CGROUP_STAT_PGPGIN_COUNT] = {"pgpgin", 1, },
+ [MEM_CGROUP_STAT_PGPGOUT_COUNT] = {"pgpgout", 1, },
};
static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
diff --git a/mm/slub.c b/mm/slub.c
index 70db2897c1e..32b62623846 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -22,6 +22,7 @@
#include <linux/debugobjects.h>
#include <linux/kallsyms.h>
#include <linux/memory.h>
+#include <linux/math64.h>
/*
* Lock order:
@@ -3621,12 +3622,10 @@ static int list_locations(struct kmem_cache *s, char *buf,
len += sprintf(buf + len, "<not-available>");
if (l->sum_time != l->min_time) {
- unsigned long remainder;
-
len += sprintf(buf + len, " age=%ld/%ld/%ld",
- l->min_time,
- div_long_long_rem(l->sum_time, l->count, &remainder),
- l->max_time);
+ l->min_time,
+ (long)div_u64(l->sum_time, l->count),
+ l->max_time);
} else
len += sprintf(buf + len, " age=%ld",
l->min_time);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 2a39cf128ab..6e45b0f3d12 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -547,6 +547,7 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
* @gfp_mask: flags for the page level allocator
* @prot: protection mask for the allocated pages
* @node: node to use for allocation or -1
+ * @caller: caller's return address
*
* Allocate enough pages to cover @size from the page level
* allocator with @gfp_mask flags. Map them into contiguous
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index eb5b9854c8c..4a1221e5e8e 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -15,8 +15,8 @@
#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/math64.h>
#include <net/tcp.h>
-#include <asm/div64.h>
#define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation
* max_cwnd = snd_cwnd * beta
@@ -128,7 +128,7 @@ static u32 cubic_root(u64 a)
* x = ( 2 * x + a / x ) / 3
* k+1 k k
*/
- x = (2 * x + (u32)div64_64(a, (u64)x * (u64)(x - 1)));
+ x = (2 * x + (u32)div64_u64(a, (u64)x * (u64)(x - 1)));
x = ((x * 341) >> 10);
return x;
}
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index b15e7e2fa14..d7e8983cd37 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -4,12 +4,11 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/skbuff.h>
+#include <linux/math64.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_connbytes.h>
#include <net/netfilter/nf_conntrack.h>
-#include <asm/div64.h>
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
@@ -82,7 +81,7 @@ connbytes_mt(const struct sk_buff *skb, const struct net_device *in,
break;
}
if (pkts != 0)
- what = div64_64(bytes, pkts);
+ what = div64_u64(bytes, pkts);
break;
}
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh
index 62e1e02126e..5552154cbed 100644
--- a/scripts/kconfig/lxdialog/check-lxdialog.sh
+++ b/scripts/kconfig/lxdialog/check-lxdialog.sh
@@ -36,8 +36,10 @@ trap "rm -f $tmp" 0 1 2 3 15
# Check if we can link to ncurses
check() {
- echo -e " #include CURSES_LOC \n main() {}" |
- $cc -xc - -o $tmp 2> /dev/null
+ $cc -xc - -o $tmp 2>/dev/null <<'EOF'
+#include CURSES_LOC
+main() {}
+EOF
if [ $? != 0 ]; then
echo " *** Unable to find the ncurses libraries or the" 1>&2
echo " *** required header files." 1>&2
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1b50a6ebc55..1c864c0efe2 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -39,6 +39,7 @@
#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/ext2_fs.h>
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index c82cf15730a..e89338e2b04 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -834,16 +834,9 @@ static const struct file_operations kvm_vcpu_fops = {
*/
static int create_vcpu_fd(struct kvm_vcpu *vcpu)
{
- int fd, r;
- struct inode *inode;
- struct file *file;
-
- r = anon_inode_getfd(&fd, &inode, &file,
- "kvm-vcpu", &kvm_vcpu_fops, vcpu);
- if (r) {
+ int fd = anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu);
+ if (fd < 0)
kvm_put_kvm(vcpu->kvm);
- return r;
- }
return fd;
}
@@ -1168,19 +1161,15 @@ static const struct file_operations kvm_vm_fops = {
static int kvm_dev_ioctl_create_vm(void)
{
- int fd, r;
- struct inode *inode;
- struct file *file;
+ int fd;
struct kvm *kvm;
kvm = kvm_create_vm();
if (IS_ERR(kvm))
return PTR_ERR(kvm);
- r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm);
- if (r) {
+ fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm);
+ if (fd < 0)
kvm_put_kvm(kvm);
- return r;
- }
return fd;
}