Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 28 Mar 2009 20:31:33 +0000 (13:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 28 Mar 2009 20:31:33 +0000 (13:31 -0700)
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6:
  [IA64] Fix kstat_this_cpu build breakage

523 files changed:
Documentation/DocBook/mac80211.tmpl
Documentation/devices.txt
Documentation/feature-removal-schedule.txt
Documentation/scsi/osd.txt [new file with mode: 0644]
MAINTAINERS
arch/alpha/kernel/entry.S
arch/alpha/kernel/osf_sys.c
arch/ia64/ia32/ia32_entry.S
arch/ia64/kernel/perfmon.c
arch/mips/kernel/linux32.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/parisc/kernel/syscall_table.S
arch/powerpc/include/asm/systbl.h
arch/s390/kernel/compat_wrapper.S
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/time_64.c
arch/um/drivers/net_kern.c
arch/um/include/shared/net_kern.h
arch/x86/ia32/ia32entry.S
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/ia32.h
arch/x86/include/asm/sys_ia32.h
block/cmd-filter.c
drivers/char/agp/intel-agp.c
drivers/firewire/fw-card.c
drivers/firewire/fw-cdev.c
drivers/firewire/fw-device.c
drivers/firewire/fw-device.h
drivers/firewire/fw-iso.c
drivers/firewire/fw-ohci.c
drivers/firewire/fw-sbp2.c
drivers/firewire/fw-topology.c
drivers/firewire/fw-topology.h
drivers/firewire/fw-transaction.c
drivers/firewire/fw-transaction.h
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_debugfs.c [new file with mode: 0644]
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_info.c [new file with mode: 0644]
drivers/gpu/drm/drm_proc.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_debugfs.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem_proc.c [deleted file]
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_bios.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_tv.c
drivers/ieee1394/csr.c
drivers/ieee1394/dv1394.c
drivers/ieee1394/eth1394.c
drivers/ieee1394/highlevel.c
drivers/ieee1394/nodemgr.c
drivers/ieee1394/nodemgr.h
drivers/ieee1394/raw1394.c
drivers/ieee1394/sbp2.c
drivers/ieee1394/video1394.c
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/media/dvb/firewire/firedtv-avc.c
drivers/mtd/mtdsuper.c
drivers/net/3c503.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/ac3200.c
drivers/net/appletalk/cops.c
drivers/net/appletalk/ltpc.c
drivers/net/at1700.c
drivers/net/benet/be_main.c
drivers/net/cs89x0.c
drivers/net/cxgb3/adapter.h
drivers/net/cxgb3/common.h
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/sge.c
drivers/net/cxgb3/t3_hw.c
drivers/net/depca.c
drivers/net/eepro.c
drivers/net/eexpress.c
drivers/net/eth16i.c
drivers/net/ethoc.c [new file with mode: 0644]
drivers/net/ewrk3.c
drivers/net/gianfar.c
drivers/net/ibmlana.c
drivers/net/irda/donauboe.c
drivers/net/lance.c
drivers/net/lp486e.c
drivers/net/ni52.c
drivers/net/ni65.c
drivers/net/seeq8005.c
drivers/net/smc-ultra.c
drivers/net/smc-ultra32.c
drivers/net/smc9194.c
drivers/net/smsc911x.c
drivers/net/tokenring/madgemc.c
drivers/net/tokenring/proteon.c
drivers/net/tokenring/skisa.c
drivers/net/tokenring/smctr.c
drivers/net/ucc_geth.c
drivers/net/wan/sdla.c
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/ar9170/Kconfig [new file with mode: 0644]
drivers/net/wireless/ar9170/Makefile [new file with mode: 0644]
drivers/net/wireless/ar9170/ar9170.h [new file with mode: 0644]
drivers/net/wireless/ar9170/cmd.c [new file with mode: 0644]
drivers/net/wireless/ar9170/cmd.h [new file with mode: 0644]
drivers/net/wireless/ar9170/eeprom.h [new file with mode: 0644]
drivers/net/wireless/ar9170/hw.h [new file with mode: 0644]
drivers/net/wireless/ar9170/led.c [new file with mode: 0644]
drivers/net/wireless/ar9170/mac.c [new file with mode: 0644]
drivers/net/wireless/ar9170/main.c [new file with mode: 0644]
drivers/net/wireless/ar9170/phy.c [new file with mode: 0644]
drivers/net/wireless/ar9170/usb.c [new file with mode: 0644]
drivers/net/wireless/ar9170/usb.h [new file with mode: 0644]
drivers/net/wireless/arlan-main.c
drivers/net/wireless/ath5k/ath5k.h
drivers/net/wireless/ath5k/attach.c
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/ath5k/base.h
drivers/net/wireless/ath5k/desc.c
drivers/net/wireless/ath5k/eeprom.c
drivers/net/wireless/ath5k/eeprom.h
drivers/net/wireless/ath5k/initvals.c
drivers/net/wireless/ath5k/led.c
drivers/net/wireless/ath5k/phy.c
drivers/net/wireless/ath5k/reg.h
drivers/net/wireless/ath5k/reset.c
drivers/net/wireless/ath9k/ahb.c
drivers/net/wireless/ath9k/ani.c
drivers/net/wireless/ath9k/ani.h
drivers/net/wireless/ath9k/ath9k.h
drivers/net/wireless/ath9k/beacon.c
drivers/net/wireless/ath9k/calib.c
drivers/net/wireless/ath9k/calib.h
drivers/net/wireless/ath9k/debug.c
drivers/net/wireless/ath9k/debug.h
drivers/net/wireless/ath9k/eeprom.c
drivers/net/wireless/ath9k/eeprom.h
drivers/net/wireless/ath9k/hw.c
drivers/net/wireless/ath9k/hw.h
drivers/net/wireless/ath9k/initvals.h
drivers/net/wireless/ath9k/mac.c
drivers/net/wireless/ath9k/mac.h
drivers/net/wireless/ath9k/main.c
drivers/net/wireless/ath9k/pci.c
drivers/net/wireless/ath9k/phy.c
drivers/net/wireless/ath9k/phy.h
drivers/net/wireless/ath9k/rc.c
drivers/net/wireless/ath9k/rc.h
drivers/net/wireless/ath9k/recv.c
drivers/net/wireless/ath9k/reg.h
drivers/net/wireless/ath9k/regd.c
drivers/net/wireless/ath9k/regd.h
drivers/net/wireless/ath9k/regd_common.h
drivers/net/wireless/ath9k/xmit.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-helpers.h
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/libertas/radiotap.h
drivers/net/wireless/libertas/rx.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/p54/Kconfig
drivers/net/wireless/p54/p54common.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/wavelan.c
drivers/net/wireless/wavelan.p.h
drivers/net/xen-netfront.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_dbf.h
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fc.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-9xxx.h
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/ch.c
drivers/scsi/constants.c
drivers/scsi/cxgb3i/cxgb3i_ddp.c
drivers/scsi/cxgb3i/cxgb3i_ddp.h
drivers/scsi/cxgb3i/cxgb3i_iscsi.c
drivers/scsi/cxgb3i/cxgb3i_offload.c
drivers/scsi/cxgb3i/cxgb3i_offload.h
drivers/scsi/cxgb3i/cxgb3i_pdu.c
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/fcoe/fcoe_sw.c
drivers/scsi/fcoe/libfcoe.c
drivers/scsi/hosts.c
drivers/scsi/hptiop.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/ips.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/libiscsi.c
drivers/scsi/libiscsi_tcp.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/mpt2sas/Kconfig [new file with mode: 0644]
drivers/scsi/mpt2sas/Makefile [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_init.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_ioc.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_raid.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_sas.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_tool.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpi/mpi2_type.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_base.c [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_base.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_config.c [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_ctl.c [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_ctl.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_debug.h [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_scsih.c [new file with mode: 0644]
drivers/scsi/mpt2sas/mpt2sas_transport.c [new file with mode: 0644]
drivers/scsi/osd/Kbuild [new file with mode: 0644]
drivers/scsi/osd/Kconfig [new file with mode: 0644]
drivers/scsi/osd/Makefile [new file with mode: 0755]
drivers/scsi/osd/osd_debug.h [new file with mode: 0644]
drivers/scsi/osd/osd_initiator.c [new file with mode: 0644]
drivers/scsi/osd/osd_uld.c [new file with mode: 0644]
drivers/scsi/osst.c
drivers/scsi/osst.h
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/ses.c
drivers/scsi/sg.c
drivers/scsi/st.c
drivers/scsi/stex.c
drivers/scsi/sym53c8xx_2/sym_glue.c
drivers/scsi/sym53c8xx_2/sym_hipd.c
drivers/scsi/sym53c8xx_2/sym_hipd.h
drivers/ssb/Kconfig
drivers/ssb/b43_pci_bridge.c
drivers/usb/storage/transport.c
fs/9p/v9fs_vfs.h
fs/9p/vfs_dentry.c
fs/9p/vfs_super.c
fs/Kconfig
fs/Makefile
fs/adfs/adfs.h
fs/adfs/dir.c
fs/affs/affs.h
fs/affs/amigaffs.c
fs/affs/namei.c
fs/afs/dir.c
fs/anon_inodes.c
fs/attr.c
fs/autofs/root.c
fs/autofs4/inode.c
fs/autofs4/root.c
fs/block_dev.c
fs/buffer.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/dir.c
fs/coda/dir.c
fs/compat.c
fs/configfs/dir.c
fs/dcache.c
fs/devpts/inode.c
fs/dlm/dir.c
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/lockspace.c
fs/dlm/lowcomms.c
fs/dlm/user.c
fs/drop_caches.c
fs/ecryptfs/dentry.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ext2/balloc.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/super.c
fs/ext2/xattr.c
fs/ext3/balloc.c
fs/ext3/ialloc.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext3/super.c
fs/ext3/xattr.c
fs/ext4/balloc.c
fs/ext4/ext4.h
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/namei.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fuse/dir.c
fs/fuse/fuse_i.h
fs/gfs2/ops_dentry.c
fs/gfs2/super.h
fs/hfs/hfs_fs.h
fs/hfs/sysdep.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hostfs/hostfs_kern.c
fs/hpfs/dentry.c
fs/inode.c
fs/isofs/inode.c
fs/jfs/acl.c
fs/jfs/inode.c
fs/jfs/jfs_dtree.c
fs/jfs/jfs_extent.c
fs/jfs/jfs_inode.c
fs/jfs/jfs_inode.h
fs/jfs/jfs_xtree.c
fs/jfs/namei.c
fs/jfs/xattr.c
fs/libfs.c
fs/namei.c
fs/namespace.c
fs/ncpfs/dir.c
fs/nfs/dir.c
fs/nfs/nfs4_fs.h
fs/nfsd/vfs.c
fs/notify/inotify/inotify.c
fs/ocfs2/dcache.c
fs/ocfs2/dcache.h
fs/open.c
fs/pipe.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/proc_sysctl.c
fs/proc/root.c
fs/quota/Kconfig [new file with mode: 0644]
fs/quota/Makefile [new file with mode: 0644]
fs/quota/dquot.c [moved from fs/dquot.c with 85% similarity]
fs/quota/quota.c [moved from fs/quota.c with 94% similarity]
fs/quota/quota_tree.c [moved from fs/quota_tree.c with 84% similarity]
fs/quota/quota_tree.h [moved from fs/quota_tree.h with 100% similarity]
fs/quota/quota_v1.c [moved from fs/quota_v1.c with 79% similarity]
fs/quota/quota_v2.c [moved from fs/quota_v2.c with 98% similarity]
fs/quota/quotaio_v1.h [moved from fs/quotaio_v1.h with 100% similarity]
fs/quota/quotaio_v2.h [moved from fs/quotaio_v2.h with 100% similarity]
fs/ramfs/file-nommu.c
fs/reiserfs/bitmap.c
fs/reiserfs/inode.c
fs/reiserfs/namei.c
fs/reiserfs/stree.c
fs/reiserfs/super.c
fs/reiserfs/xattr.c
fs/smbfs/dir.c
fs/super.c
fs/sync.c
fs/sysfs/dir.c
fs/sysv/namei.c
fs/sysv/sysv.h
fs/ubifs/super.c
fs/udf/balloc.c
fs/udf/ialloc.c
fs/ufs/balloc.c
fs/ufs/ialloc.c
fs/ufs/inode.c
fs/ufs/namei.c
fs/ufs/super.c
fs/ufs/ufs.h
include/drm/drmP.h
include/drm/drm_pciids.h
include/linux/bsg.h
include/linux/buffer_head.h
include/linux/compat.h
include/linux/dcache.h
include/linux/firewire-cdev.h
include/linux/fs.h
include/linux/ieee80211.h
include/linux/if_ether.h
include/linux/if_frad.h
include/linux/major.h
include/linux/miscdevice.h
include/linux/ncp_fs.h
include/linux/netdevice.h
include/linux/netfilter/x_tables.h
include/linux/nfs_fs.h
include/linux/nfs_xdr.h
include/linux/nl80211.h
include/linux/pci_ids.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/skbuff.h
include/net/cfg80211.h
include/net/ethoc.h [new file with mode: 0644]
include/net/ieee80211_radiotap.h
include/net/mac80211.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_conntrack_helper.h
include/net/netfilter/nf_conntrack_l3proto.h
include/net/netfilter/nf_conntrack_l4proto.h
include/net/netfilter/nf_conntrack_tuple.h
include/net/netlink.h
include/net/netns/conntrack.h
include/scsi/fc/fc_fcoe.h
include/scsi/fc_frame.h
include/scsi/libfc.h
include/scsi/libfcoe.h
include/scsi/libiscsi.h
include/scsi/osd_attributes.h [new file with mode: 0644]
include/scsi/osd_initiator.h [new file with mode: 0644]
include/scsi/osd_protocol.h [new file with mode: 0644]
include/scsi/osd_sec.h [new file with mode: 0644]
include/scsi/osd_sense.h [new file with mode: 0644]
include/scsi/osd_types.h [new file with mode: 0644]
include/scsi/scsi.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_device.h
include/scsi/scsi_transport_iscsi.h
kernel/cgroup.c
lib/nlattr.c
net/appletalk/ddp.c
net/ax25/af_ax25.c
net/core/dev.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv6/ip6_input.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wep.c
net/mac80211/wext.c
net/mac80211/wpa.c
net/netfilter/Kconfig
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_proto_udp.c
net/netfilter/nf_conntrack_proto_udplite.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/xt_connlimit.c
net/netfilter/xt_physdev.c
net/netrom/af_netrom.c
net/rose/af_rose.c
net/socket.c
net/sunrpc/rpc_pipe.c
net/wireless/Kconfig
net/wireless/Makefile
net/wireless/core.c
net/wireless/core.h
net/wireless/mlme.c [new file with mode: 0644]
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/scan.c
net/wireless/wext-compat.c
net/x25/af_x25.c
net/xfrm/xfrm_state.c

index 8af6d9626878e0459c02052081c41bbc33c5d20d..fbeaffc1dcc39c7b25e3f36cc7923828be9cbec9 100644 (file)
@@ -227,6 +227,12 @@ usage should require reading the full document.
 !Pinclude/net/mac80211.h Powersave support
     </chapter>
 
+    <chapter id="beacon-filter">
+      <title>Beacon filter support</title>
+!Pinclude/net/mac80211.h Beacon filter support
+!Finclude/net/mac80211.h ieee80211_beacon_loss
+    </chapter>
+
     <chapter id="qos">
       <title>Multiple queues and QoS support</title>
       <para>TBD</para>
index 2be08240ee8061e6a55773938252a1fe888fe3c7..62254d4510c6c8e716733d9a46d12dd17c7052b1 100644 (file)
@@ -3145,6 +3145,12 @@ Your cooperation is appreciated.
                  1 = /dev/blockrom1    Second ROM card's translation layer interface
                  ...
 
+260 char       OSD (Object-based-device) SCSI Device
+                 0 = /dev/osd0         First OSD Device
+                 1 = /dev/osd1         Second OSD Device
+                 ...
+                 255 = /dev/osd255     256th OSD Device
+
  ****  ADDITIONAL /dev DIRECTORY ENTRIES
 
 This section details additional entries that should or may exist in
index e47c0ff8ba7aaf59d8d6fa8776ab331b9c5c25b6..02ea3773535e1fba8f7c7c931b04f7a1e1b7074d 100644 (file)
@@ -6,20 +6,47 @@ be removed from this file.
 
 ---------------------------
 
-What:  old static regulatory information and ieee80211_regdom module parameter
-When:  2.6.29
+What:  The ieee80211_regdom module parameter
+When:  March 2010 / desktop catchup
+
+Why:   This was inherited by the CONFIG_WIRELESS_OLD_REGULATORY code,
+       and currently serves as an option for users to define an
+       ISO / IEC 3166 alpha2 code for the country they are currently
+       present in. Although there are userspace API replacements for this
+       through nl80211 distributions haven't yet caught up with implementing
+       decent alternatives through standard GUIs. Although available as an
+       option through iw or wpa_supplicant its just a matter of time before
+       distributions pick up good GUI options for this. The ideal solution
+       would actually consist of intelligent designs which would do this for
+       the user automatically even when travelling through different countries.
+       Until then we leave this module parameter as a compromise.
+
+       When userspace improves with reasonable widely-available alternatives for
+       this we will no longer need this module parameter. This entry hopes that
+       by the super-futuristically looking date of "March 2010" we will have
+       such replacements widely available.
+
+Who:   Luis R. Rodriguez <lrodriguez@atheros.com>
+
+---------------------------
+
+What:  CONFIG_WIRELESS_OLD_REGULATORY - old static regulatory information
+When:  March 2010 / desktop catchup
+
 Why:   The old regulatory infrastructure has been replaced with a new one
        which does not require statically defined regulatory domains. We do
        not want to keep static regulatory domains in the kernel due to the
        the dynamic nature of regulatory law and localization. We kept around
        the old static definitions for the regulatory domains of:
+
                * US
                * JP
                * EU
+
        and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was
-       set. We also kept around the ieee80211_regdom module parameter in case
-       some applications were relying on it. Changing regulatory domains
-       can now be done instead by using nl80211, as is done with iw.
+       set. We will remove this option once the standard Linux desktop catches
+       up with the new userspace APIs we have implemented.
+
 Who:   Luis R. Rodriguez <lrodriguez@atheros.com>
 
 ---------------------------
diff --git a/Documentation/scsi/osd.txt b/Documentation/scsi/osd.txt
new file mode 100644 (file)
index 0000000..da162f7
--- /dev/null
@@ -0,0 +1,198 @@
+The OSD Standard
+================
+OSD (Object-Based Storage Device) is a T10 SCSI command set that is designed
+to provide efficient operation of input/output logical units that manage the
+allocation, placement, and accessing of variable-size data-storage containers,
+called objects. Objects are intended to contain operating system and application
+constructs. Each object has associated attributes attached to it, which are
+integral part of the object and provide metadata about the object. The standard
+defines some common obligatory attributes, but user attributes can be added as
+needed.
+
+See: http://www.t10.org/ftp/t10/drafts/osd2/ for the latest draft for OSD 2
+or search the web for "OSD SCSI"
+
+OSD in the Linux Kernel
+=======================
+osd-initiator:
+  The main component of OSD in Kernel is the osd-initiator library. Its main
+user is intended to be the pNFS-over-objects layout driver, which uses objects
+as its back-end data storage. Other clients are the other osd parts listed below.
+
+osd-uld:
+  This is a SCSI ULD that registers for OSD type devices and provides a testing
+platform, both for the in-kernel initiator as well as connected targets. It
+currently has no useful user-mode API, though it could have if need be.
+
+exofs:
+  Is an OSD based Linux file system. It uses the osd-initiator and osd-uld,
+to export a usable file system for users.
+See Documentation/filesystems/exofs.txt for more details
+
+osd target:
+  There are no current plans for an OSD target implementation in kernel. For all
+needs, a user-mode target that is based on the scsi tgt target framework is
+available from Ohio Supercomputer Center (OSC) at:
+http://www.open-osd.org/bin/view/Main/OscOsdProject
+There are several other target implementations. See http://open-osd.org for more
+links.
+
+Files and Folders
+=================
+This is the complete list of files included in this work:
+include/scsi/
+       osd_initiator.h   Main API for the initiator library
+       osd_types.h       Common OSD types
+       osd_sec.h         Security Manager API
+       osd_protocol.h    Wire definitions of the OSD standard protocol
+       osd_attributes.h  Wire definitions of OSD attributes
+
+drivers/scsi/osd/
+       osd_initiator.c   OSD-Initiator library implementation
+       osd_uld.c         The OSD scsi ULD
+       osd_ktest.{h,c}   In-kernel test suite (called by osd_uld)
+       osd_debug.h       Some printk macros
+       Makefile          For both in-tree and out-of-tree compilation
+       Kconfig           Enables inclusion of the different pieces
+       osd_test.c        User-mode application to call the kernel tests
+
+The OSD-Initiator Library
+=========================
+osd_initiator is a low level implementation of an osd initiator encoder.
+But even though, it should be intuitive and easy to use. Perhaps over time an
+higher lever will form that automates some of the more common recipes.
+
+init/fini:
+- osd_dev_init() associates a scsi_device with an osd_dev structure
+  and initializes some global pools. This should be done once per scsi_device
+  (OSD LUN). The osd_dev structure is needed for calling osd_start_request().
+
+- osd_dev_fini() cleans up before a osd_dev/scsi_device destruction.
+
+OSD commands encoding, execution, and decoding of results:
+
+struct osd_request's is used to iteratively encode an OSD command and carry
+its state throughout execution. Each request goes through these stages:
+
+a. osd_start_request() allocates the request.
+
+b. Any of the osd_req_* methods is used to encode a request of the specified
+   type.
+
+c. osd_req_add_{get,set}_attr_* may be called to add get/set attributes to the
+   CDB. "List" or "Page" mode can be used exclusively. The attribute-list API
+   can be called multiple times on the same request. However, only one
+   attribute-page can be read, as mandated by the OSD standard.
+
+d. osd_finalize_request() computes offsets into the data-in and data-out buffers
+   and signs the request using the provided capability key and integrity-
+   check parameters.
+
+e. osd_execute_request() may be called to execute the request via the block
+   layer and wait for its completion.  The request can be executed
+   asynchronously by calling the block layer API directly.
+
+f. After execution, osd_req_decode_sense() can be called to decode the request's
+   sense information.
+
+g. osd_req_decode_get_attr() may be called to retrieve osd_add_get_attr_list()
+   values.
+
+h. osd_end_request() must be called to deallocate the request and any resource
+   associated with it. Note that osd_end_request cleans up the request at any
+   stage and it must always be called after a successful osd_start_request().
+
+osd_request's structure:
+
+The OSD standard defines a complex structure of IO segments pointed to by
+members in the CDB. Up to 3 segments can be deployed in the IN-Buffer and up to
+4 in the OUT-Buffer. The ASCII illustration below depicts a secure-read with
+associated get+set of attributes-lists. Other combinations very on the same
+basic theme. From no-segments-used up to all-segments-used.
+
+|________OSD-CDB__________|
+|                         |
+|read_len (offset=0)     -|---------\
+|                         |         |
+|get_attrs_list_length    |         |
+|get_attrs_list_offset   -|----\    |
+|                         |    |    |
+|retrieved_attrs_alloc_len|    |    |
+|retrieved_attrs_offset  -|----|----|-\
+|                         |    |    | |
+|set_attrs_list_length    |    |    | |
+|set_attrs_list_offset   -|-\  |    | |
+|                         | |  |    | |
+|in_data_integ_offset    -|-|--|----|-|-\
+|out_data_integ_offset   -|-|--|--\ | | |
+\_________________________/ |  |  | | | |
+                            |  |  | | | |
+|_______OUT-BUFFER________| |  |  | | | |
+|      Set attr list      |</  |  | | | |
+|                         |    |  | | | |
+|-------------------------|    |  | | | |
+|   Get attr descriptors  |<---/  | | | |
+|                         |       | | | |
+|-------------------------|       | | | |
+|    Out-data integrity   |<------/ | | |
+|                         |         | | |
+\_________________________/         | | |
+                                    | | |
+|________IN-BUFFER________|         | | |
+|      In-Data read       |<--------/ | |
+|                         |           | |
+|-------------------------|           | |
+|      Get attr list      |<----------/ |
+|                         |             |
+|-------------------------|             |
+|    In-data integrity    |<------------/
+|                         |
+\_________________________/
+
+A block device request can carry bidirectional payload by means of associating
+a bidi_read request with a main write-request. Each in/out request is described
+by a chain of BIOs associated with each request.
+The CDB is of a SCSI VARLEN CDB format, as described by OSD standard.
+The OSD standard also mandates alignment restrictions at start of each segment.
+
+In the code, in struct osd_request, there are two _osd_io_info structures to
+describe the IN/OUT buffers above, two BIOs for the data payload and up to five
+_osd_req_data_segment structures to hold the different segments allocation and
+information.
+
+Important: We have chosen to disregard the assumption that a BIO-chain (and
+the resulting sg-list) describes a linear memory buffer. Meaning only first and
+last scatter chain can be incomplete and all the middle chains are of PAGE_SIZE.
+For us, a scatter-gather-list, as its name implies and as used by the Networking
+layer, is to describe a vector of buffers that will be transferred to/from the
+wire. It works very well with current iSCSI transport. iSCSI is currently the
+only deployed OSD transport. In the future we anticipate SAS and FC attached OSD
+devices as well.
+
+The OSD Testing ULD
+===================
+TODO: More user-mode control on tests.
+
+Authors, Mailing list
+=====================
+Please communicate with us on any deployment of osd, whether using this code
+or not.
+
+Any problems, questions, bug reports, lonely OSD nights, please email:
+   OSD Dev List <osd-dev@open-osd.org>
+
+More up-to-date information can be found on:
+http://open-osd.org
+
+Boaz Harrosh <bharrosh@panasas.com>
+Benny Halevy <bhalevy@panasas.com>
+
+References
+==========
+Weber, R., "SCSI Object-Based Storage Device Commands",
+T10/1355-D ANSI/INCITS 400-2004,
+http://www.t10.org/ftp/t10/drafts/osd/osd-r10.pdf
+
+Weber, R., "SCSI Object-Based Storage Device Commands -2 (OSD-2)"
+T10/1729-D, Working Draft, rev. 3
+http://www.t10.org/ftp/t10/drafts/osd2/osd2r03.pdf
index fa7be04b0cf0f2fb4d448b86d3dc122b39a22df6..d8a4c8d0a5544bbbe9d749b858eb4d4fbb1d13c3 100644 (file)
@@ -765,6 +765,14 @@ L: linux-wireless@vger.kernel.org
 L:     ath9k-devel@lists.ath9k.org
 S:     Supported
 
+ATHEROS AR9170 WIRELESS DRIVER
+P:     Christian Lamparter
+M:     chunkeey@web.de
+L:     linux-wireless@vger.kernel.org
+W:     http://wireless.kernel.org/en/users/Drivers/ar9170
+S:     Maintained
+F:     drivers/net/wireless/ar9170/
+
 ATI_REMOTE2 DRIVER
 P:     Ville Syrjala
 M:     syrjala@sci.fi
@@ -3302,6 +3310,16 @@ L:       orinoco-devel@lists.sourceforge.net
 W:     http://www.nongnu.org/orinoco/
 S:     Maintained
 
+OSD LIBRARY
+P:     Boaz Harrosh
+M:     bharrosh@panasas.com
+P:     Benny Halevy
+M:     bhalevy@panasas.com
+L:     osd-dev@open-osd.org
+W:     http://open-osd.org
+T:     git://git.open-osd.org/open-osd.git
+S:     Maintained
+
 P54 WIRELESS DRIVER
 P:     Michael Wu
 M:     flamingice@sourmilk.net
@@ -3602,7 +3620,7 @@ S:        Maintained
 RALINK RT2X00 WIRELESS LAN DRIVER
 P:     rt2x00 project
 L:     linux-wireless@vger.kernel.org
-L:     rt2400-devel@lists.sourceforge.net
+L:     users@rt2x00.serialmonkey.com
 W:     http://rt2x00.serialmonkey.com/
 S:     Maintained
 T:     git kernel.org:/pub/scm/linux/kernel/git/ivd/rt2x00.git
index e4a54b615894f270b97fbf3a9ddd348e2abcae3a..b45d913a51c368881b4311d1f1887566829b09a8 100644 (file)
@@ -903,8 +903,9 @@ sys_alpha_pipe:
        stq     $26, 0($sp)
        .prologue 0
 
+       mov     $31, $17
        lda     $16, 8($sp)
-       jsr     $26, do_pipe
+       jsr     $26, do_pipe_flags
 
        ldq     $26, 0($sp)
        bne     $0, 1f
index ae41f097864b8ccc1ee49622dd96e6a88d8d4f39..42ee05981e7173d39ac6e047dabce5b46075669b 100644 (file)
@@ -46,8 +46,6 @@
 #include <asm/hwrpb.h>
 #include <asm/processor.h>
 
-extern int do_pipe(int *);
-
 /*
  * Brk needs to return an error.  Still support Linux's brk(0) query idiom,
  * which OSF programs just shouldn't be doing.  We're still not quite
index a46f8395e9a51857b0c0364a8b80733bd0575d64..af9405cd70e5fa36a3f786958a4fa0cc0a5cc300 100644 (file)
@@ -240,7 +240,7 @@ ia32_syscall_table:
        data8 sys_ni_syscall
        data8 sys_umask           /* 60 */
        data8 sys_chroot
-       data8 sys_ustat
+       data8 compat_sys_ustat
        data8 sys_dup2
        data8 sys_getppid
        data8 sys_getpgrp         /* 65 */
index 0e499757309bfbdab35d1233126e4259d9f42bdd..5c0f408cfd719f02ded2c58dc6ebf2b3c181c7b5 100644 (file)
@@ -2196,7 +2196,7 @@ pfmfs_delete_dentry(struct dentry *dentry)
        return 1;
 }
 
-static struct dentry_operations pfmfs_dentry_operations = {
+static const struct dentry_operations pfmfs_dentry_operations = {
        .d_delete = pfmfs_delete_dentry,
 };
 
index 49aac6e17df932a89658840302c7332a8c27f012..2a472713de8e535353ec32718b181a8405b487a6 100644 (file)
@@ -355,40 +355,6 @@ SYSCALL_DEFINE1(32_personality, unsigned long, personality)
        return ret;
 }
 
-/* ustat compatibility */
-struct ustat32 {
-       compat_daddr_t  f_tfree;
-       compat_ino_t    f_tinode;
-       char            f_fname[6];
-       char            f_fpack[6];
-};
-
-extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf);
-
-SYSCALL_DEFINE2(32_ustat, dev_t, dev, struct ustat32 __user *, ubuf32)
-{
-       int err;
-       struct ustat tmp;
-       struct ustat32 tmp32;
-       mm_segment_t old_fs = get_fs();
-
-       set_fs(KERNEL_DS);
-       err = sys_ustat(dev, (struct ustat __user *)&tmp);
-       set_fs(old_fs);
-
-       if (err)
-               goto out;
-
-       memset(&tmp32, 0, sizeof(struct ustat32));
-       tmp32.f_tfree = tmp.f_tfree;
-       tmp32.f_tinode = tmp.f_tinode;
-
-       err = copy_to_user(ubuf32, &tmp32, sizeof(struct ustat32)) ? -EFAULT : 0;
-
-out:
-       return err;
-}
-
 SYSCALL_DEFINE4(32_sendfile, long, out_fd, long, in_fd,
        compat_off_t __user *, offset, s32, count)
 {
index 7438e92f8a010566e183f986190b14de82e70bd7..f61d6b0e5731dadfcac24715babed10639ce97d2 100644 (file)
@@ -253,7 +253,7 @@ EXPORT(sysn32_call_table)
        PTR     compat_sys_utime                /* 6130 */
        PTR     sys_mknod
        PTR     sys_32_personality
-       PTR     sys_32_ustat
+       PTR     compat_sys_ustat
        PTR     compat_sys_statfs
        PTR     compat_sys_fstatfs              /* 6135 */
        PTR     sys_sysfs
index b0fef4ff9827610210ef3dc16d903d347491169d..60997f1f69d4e857861df014ab37e403f1d53c60 100644 (file)
@@ -265,7 +265,7 @@ sys_call_table:
        PTR     sys_olduname
        PTR     sys_umask                       /* 4060 */
        PTR     sys_chroot
-       PTR     sys_32_ustat
+       PTR     compat_sys_ustat
        PTR     sys_dup2
        PTR     sys_getppid
        PTR     sys_getpgrp                     /* 4065 */
index 303d2b647e418daab682f586565ade19e5420325..03b9a01bc16cf49340db4d69329a08338e47650f 100644 (file)
        ENTRY_OURS(newuname)
        ENTRY_SAME(umask)               /* 60 */
        ENTRY_SAME(chroot)
-       ENTRY_SAME(ustat)
+       ENTRY_COMP(ustat)
        ENTRY_SAME(dup2)
        ENTRY_SAME(getppid)
        ENTRY_SAME(getpgrp)             /* 65 */
index 72353f6070a436747817d2394c8e8f9ff67898b0..fe166491e9dcf9a821fb10be53678b48a3f3578e 100644 (file)
@@ -65,7 +65,7 @@ SYSCALL(ni_syscall)
 SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
 COMPAT_SYS_SPU(umask)
 SYSCALL_SPU(chroot)
-SYSCALL(ustat)
+COMPAT_SYS(ustat)
 SYSCALL_SPU(dup2)
 SYSCALL_SPU(getppid)
 SYSCALL_SPU(getpgrp)
index 62c706eb0de6d427401a2325dbb73e6982eec6a8..87cf5a79a351c38e5dfed555fca336b3fe6e3575 100644 (file)
@@ -252,7 +252,7 @@ sys32_chroot_wrapper:
 sys32_ustat_wrapper:
        llgfr   %r2,%r2                 # dev_t
        llgtr   %r3,%r3                 # struct ustat *
-       jg      sys_ustat
+       jg      compat_sys_ustat
 
        .globl  sys32_dup2_wrapper
 sys32_dup2_wrapper:
index 6cd1a5b650673c3a4ba0cb74f94fb32084d76aee..79457f682b5ac05b693d185223ddd7ea8f9335b6 100644 (file)
@@ -1031,7 +1031,7 @@ void smp_fetch_global_regs(void)
  *    If the address space is non-shared (ie. mm->count == 1) we avoid
  *    cross calls when we want to flush the currently running process's
  *    tlb state.  This is done by clearing all cpu bits except the current
- *    processor's in current->active_mm->cpu_vm_mask and performing the
+ *    processor's in current->mm->cpu_vm_mask and performing the
  *    flush locally only.  This will force any subsequent cpus which run
  *    this task to flush the context from the local tlb if the process
  *    migrates to another cpu (again).
@@ -1074,7 +1074,7 @@ void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long
        u32 ctx = CTX_HWBITS(mm->context);
        int cpu = get_cpu();
 
-       if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1)
+       if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
                mm->cpu_vm_mask = cpumask_of_cpu(cpu);
        else
                smp_cross_call_masked(&xcall_flush_tlb_pending,
index f93c42a2b52215696be05ea022d74db09763bb21..a8000b1cda74d60ee726ff0fc76a7e556093e1f8 100644 (file)
@@ -51,7 +51,7 @@ sys_call_table32:
 /*150*/        .word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
        .word compat_sys_fcntl64, sys_inotify_rm_watch, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount
 /*160*/        .word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys32_getdomainname, sys32_setdomainname, sys_nis_syscall
-       .word sys_quotactl, sys_set_tid_address, compat_sys_mount, sys_ustat, sys32_setxattr
+       .word sys_quotactl, sys_set_tid_address, compat_sys_mount, compat_sys_ustat, sys32_setxattr
 /*170*/        .word sys32_lsetxattr, sys32_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents
        .word sys_setsid, sys_fchdir, sys32_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/        .word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
index 642562d83ec44603dddfbc6276fcb7a2e52a211d..4ee2e48c4b392c84ca1db5870778a7d3645e24cc 100644 (file)
@@ -724,12 +724,14 @@ void timer_interrupt(int irq, struct pt_regs *regs)
        unsigned long tick_mask = tick_ops->softint_mask;
        int cpu = smp_processor_id();
        struct clock_event_device *evt = &per_cpu(sparc64_events, cpu);
+       struct irq_desc *desc;
 
        clear_softint(tick_mask);
 
        irq_enter();
 
-       kstat_this_cpu.irqs[0]++;
+       desc = irq_to_desc(0);
+       kstat_incr_irqs_this_cpu(0, desc);
 
        if (unlikely(!evt->event_handler)) {
                printk(KERN_WARNING
index fde510b664d34db07ecab00ea48d285adefd2703..434224e2229ff6afde1556b5541b83200466c99e 100644 (file)
@@ -86,7 +86,7 @@ static int uml_net_rx(struct net_device *dev)
                drop_skb->dev = dev;
                /* Read a packet into drop_skb and don't do anything with it. */
                (*lp->read)(lp->fd, drop_skb, lp);
-               lp->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
                return 0;
        }
 
@@ -99,8 +99,8 @@ static int uml_net_rx(struct net_device *dev)
                skb_trim(skb, pkt_len);
                skb->protocol = (*lp->protocol)(skb);
 
-               lp->stats.rx_bytes += skb->len;
-               lp->stats.rx_packets++;
+               dev->stats.rx_bytes += skb->len;
+               dev->stats.rx_packets++;
                netif_rx(skb);
                return pkt_len;
        }
@@ -224,8 +224,8 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
        len = (*lp->write)(lp->fd, skb, lp);
 
        if (len == skb->len) {
-               lp->stats.tx_packets++;
-               lp->stats.tx_bytes += skb->len;
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += skb->len;
                dev->trans_start = jiffies;
                netif_start_queue(dev);
 
@@ -234,7 +234,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        else if (len == 0) {
                netif_start_queue(dev);
-               lp->stats.tx_dropped++;
+               dev->stats.tx_dropped++;
        }
        else {
                netif_start_queue(dev);
@@ -248,12 +248,6 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
-static struct net_device_stats *uml_net_get_stats(struct net_device *dev)
-{
-       struct uml_net_private *lp = netdev_priv(dev);
-       return &lp->stats;
-}
-
 static void uml_net_set_multicast_list(struct net_device *dev)
 {
        return;
@@ -377,6 +371,18 @@ static void net_device_release(struct device *dev)
        free_netdev(netdev);
 }
 
+static const struct net_device_ops uml_netdev_ops = {
+       .ndo_open               = uml_net_open,
+       .ndo_stop               = uml_net_close,
+       .ndo_start_xmit         = uml_net_start_xmit,
+       .ndo_set_multicast_list = uml_net_set_multicast_list,
+       .ndo_tx_timeout         = uml_net_tx_timeout,
+       .ndo_set_mac_address    = uml_net_set_mac,
+       .ndo_change_mtu         = uml_net_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /*
  * Ensures that platform_driver_register is called only once by
  * eth_configure.  Will be set in an initcall.
@@ -473,14 +479,7 @@ static void eth_configure(int n, void *init, char *mac,
 
        set_ether_mac(dev, device->mac);
        dev->mtu = transport->user->mtu;
-       dev->open = uml_net_open;
-       dev->hard_start_xmit = uml_net_start_xmit;
-       dev->stop = uml_net_close;
-       dev->get_stats = uml_net_get_stats;
-       dev->set_multicast_list = uml_net_set_multicast_list;
-       dev->tx_timeout = uml_net_tx_timeout;
-       dev->set_mac_address = uml_net_set_mac;
-       dev->change_mtu = uml_net_change_mtu;
+       dev->netdev_ops = &uml_netdev_ops;
        dev->ethtool_ops = &uml_net_ethtool_ops;
        dev->watchdog_timeo = (HZ >> 1);
        dev->irq = UM_ETH_IRQ;
index d843c7924a7cf2568a1ce88ff9182a52f4ccc322..5c367f22595bd5bf915b4c55e33892d4833f17e5 100644 (file)
@@ -26,7 +26,7 @@ struct uml_net_private {
        spinlock_t lock;
        struct net_device *dev;
        struct timer_list tl;
-       struct net_device_stats stats;
+
        struct work_struct work;
        int fd;
        unsigned char mac[ETH_ALEN];
index 5a0d76dc56a46431690702be8f745d6813db4cfc..8ef8876666b2ed5aaabcc6f21d7129fde453ca75 100644 (file)
@@ -557,7 +557,7 @@ ia32_sys_call_table:
        .quad sys32_olduname
        .quad sys_umask         /* 60 */
        .quad sys_chroot
-       .quad sys32_ustat
+       .quad compat_sys_ustat
        .quad sys_dup2
        .quad sys_getppid
        .quad sys_getpgrp               /* 65 */
index 6c0d7f6231af26e3eb3fb26821d4dbf493233fc2..efac92fd1efbc3f3a7b1fa923b0314e951249555 100644 (file)
@@ -638,28 +638,6 @@ long sys32_uname(struct old_utsname __user *name)
        return err ? -EFAULT : 0;
 }
 
-long sys32_ustat(unsigned dev, struct ustat32 __user *u32p)
-{
-       struct ustat u;
-       mm_segment_t seg;
-       int ret;
-
-       seg = get_fs();
-       set_fs(KERNEL_DS);
-       ret = sys_ustat(dev, (struct ustat __user *)&u);
-       set_fs(seg);
-       if (ret < 0)
-               return ret;
-
-       if (!access_ok(VERIFY_WRITE, u32p, sizeof(struct ustat32)) ||
-           __put_user((__u32) u.f_tfree, &u32p->f_tfree) ||
-           __put_user((__u32) u.f_tinode, &u32p->f_tfree) ||
-           __copy_to_user(&u32p->f_fname, u.f_fname, sizeof(u.f_fname)) ||
-           __copy_to_user(&u32p->f_fpack, u.f_fpack, sizeof(u.f_fpack)))
-               ret = -EFAULT;
-       return ret;
-}
-
 asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
                             compat_uptr_t __user *envp, struct pt_regs *regs)
 {
index 50ca486fd88c9468fe52b4a9fb357f192fbd6ab0..1f7e62517284618d6fd08aad123f6e34da8caa26 100644 (file)
@@ -129,13 +129,6 @@ typedef struct compat_siginfo {
        } _sifields;
 } compat_siginfo_t;
 
-struct ustat32 {
-       __u32                   f_tfree;
-       compat_ino_t            f_tinode;
-       char                    f_fname[6];
-       char                    f_fpack[6];
-};
-
 #define IA32_STACK_TOP IA32_PAGE_OFFSET
 
 #ifdef __KERNEL__
index ffb08be2a5303405c1a5629766f84f1964018a3b..72a6dcd1299b6154562f5717c9ef751a9e287dc2 100644 (file)
@@ -70,8 +70,6 @@ struct old_utsname;
 asmlinkage long sys32_olduname(struct oldold_utsname __user *);
 long sys32_uname(struct old_utsname __user *);
 
-long sys32_ustat(unsigned, struct ustat32 __user *);
-
 asmlinkage long sys32_execve(char __user *, compat_uptr_t __user *,
                             compat_uptr_t __user *, struct pt_regs *);
 asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *);
index 504b275e1b905a5ffe6d42695acbefe6fd0fff55..572bbc2f900d89992da0b35d22b16c894e847adf 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/spinlock.h>
 #include <linux/capability.h>
 #include <linux/bitops.h>
+#include <linux/blkdev.h>
 
 #include <scsi/scsi.h>
 #include <linux/cdrom.h>
index 4373adb2119aeea256758abc7602504477d5c5ad..9d9490e22e07abd728fa52fa2d003df22c8b1175 100644 (file)
 #define PCI_DEVICE_ID_INTEL_82965GME_IG     0x2A12
 #define PCI_DEVICE_ID_INTEL_82945GME_HB     0x27AC
 #define PCI_DEVICE_ID_INTEL_82945GME_IG     0x27AE
+#define PCI_DEVICE_ID_INTEL_IGDGM_HB        0xA010
+#define PCI_DEVICE_ID_INTEL_IGDGM_IG        0xA011
+#define PCI_DEVICE_ID_INTEL_IGDG_HB         0xA000
+#define PCI_DEVICE_ID_INTEL_IGDG_IG         0xA001
 #define PCI_DEVICE_ID_INTEL_G33_HB          0x29C0
 #define PCI_DEVICE_ID_INTEL_G33_IG          0x29C2
 #define PCI_DEVICE_ID_INTEL_Q35_HB          0x29B0
 
 #define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB)
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDGM_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDG_HB)
+
+#define IS_IGD (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDGM_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDG_HB)
 
 #define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_E_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
@@ -510,7 +519,7 @@ static void intel_i830_init_gtt_entries(void)
                        size = 512;
                }
                size += 4; /* add in BIOS popup space */
-       } else if (IS_G33) {
+       } else if (IS_G33 && !IS_IGD) {
        /* G33's GTT size defined in gmch_ctrl */
                switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
                case G33_PGETBL_SIZE_1M:
@@ -526,7 +535,7 @@ static void intel_i830_init_gtt_entries(void)
                        size = 512;
                }
                size += 4;
-       } else if (IS_G4X) {
+       } else if (IS_G4X || IS_IGD) {
                /* On 4 series hardware, GTT stolen is separate from graphics
                 * stolen, ignore it in stolen gtt entries counting.  However,
                 * 4KB of the stolen memory doesn't get mapped to the GTT.
@@ -2161,6 +2170,10 @@ static const struct intel_driver_description {
                NULL, &intel_g33_driver },
        { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
                NULL, &intel_g33_driver },
+       { PCI_DEVICE_ID_INTEL_IGDGM_HB, PCI_DEVICE_ID_INTEL_IGDGM_IG, 0, "IGD",
+               NULL, &intel_g33_driver },
+       { PCI_DEVICE_ID_INTEL_IGDG_HB, PCI_DEVICE_ID_INTEL_IGDG_IG, 0, "IGD",
+               NULL, &intel_g33_driver },
        { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
            "Mobile IntelĀ® GM45 Express", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_IGD_E_HB, PCI_DEVICE_ID_INTEL_IGD_E_IG, 0,
@@ -2355,6 +2368,8 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_82945G_HB),
        ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
        ID(PCI_DEVICE_ID_INTEL_82945GME_HB),
+       ID(PCI_DEVICE_ID_INTEL_IGDGM_HB),
+       ID(PCI_DEVICE_ID_INTEL_IGDG_HB),
        ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
        ID(PCI_DEVICE_ID_INTEL_82G35_HB),
        ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
index a5dd7a665aa89e1551dd89653af01234a0d2adc8..8b8c8c22f0fce384229eab085210a1aea4353cc8 100644 (file)
@@ -63,8 +63,7 @@ static int descriptor_count;
 #define BIB_CMC                        ((1) << 30)
 #define BIB_IMC                        ((1) << 31)
 
-static u32 *
-generate_config_rom(struct fw_card *card, size_t *config_rom_length)
+static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
 {
        struct fw_descriptor *desc;
        static u32 config_rom[256];
@@ -128,8 +127,7 @@ generate_config_rom(struct fw_card *card, size_t *config_rom_length)
        return config_rom;
 }
 
-static void
-update_config_roms(void)
+static void update_config_roms(void)
 {
        struct fw_card *card;
        u32 *config_rom;
@@ -141,8 +139,7 @@ update_config_roms(void)
        }
 }
 
-int
-fw_core_add_descriptor(struct fw_descriptor *desc)
+int fw_core_add_descriptor(struct fw_descriptor *desc)
 {
        size_t i;
 
@@ -171,8 +168,7 @@ fw_core_add_descriptor(struct fw_descriptor *desc)
        return 0;
 }
 
-void
-fw_core_remove_descriptor(struct fw_descriptor *desc)
+void fw_core_remove_descriptor(struct fw_descriptor *desc)
 {
        mutex_lock(&card_mutex);
 
@@ -185,12 +181,30 @@ fw_core_remove_descriptor(struct fw_descriptor *desc)
        mutex_unlock(&card_mutex);
 }
 
+static int set_broadcast_channel(struct device *dev, void *data)
+{
+       fw_device_set_broadcast_channel(fw_device(dev), (long)data);
+       return 0;
+}
+
+static void allocate_broadcast_channel(struct fw_card *card, int generation)
+{
+       int channel, bandwidth = 0;
+
+       fw_iso_resource_manage(card, generation, 1ULL << 31,
+                              &channel, &bandwidth, true);
+       if (channel == 31) {
+               card->broadcast_channel_allocated = true;
+               device_for_each_child(card->device, (void *)(long)generation,
+                                     set_broadcast_channel);
+       }
+}
+
 static const char gap_count_table[] = {
        63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40
 };
 
-void
-fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
+void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
 {
        int scheduled;
 
@@ -200,37 +214,38 @@ fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
                fw_card_put(card);
 }
 
-static void
-fw_card_bm_work(struct work_struct *work)
+static void fw_card_bm_work(struct work_struct *work)
 {
        struct fw_card *card = container_of(work, struct fw_card, work.work);
        struct fw_device *root_device;
-       struct fw_node *root_node, *local_node;
+       struct fw_node *root_node;
        unsigned long flags;
-       int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
+       int root_id, new_root_id, irm_id, local_id;
+       int gap_count, generation, grace, rcode;
        bool do_reset = false;
        bool root_device_is_running;
        bool root_device_is_cmc;
        __be32 lock_data[2];
 
        spin_lock_irqsave(&card->lock, flags);
-       local_node = card->local_node;
-       root_node  = card->root_node;
 
-       if (local_node == NULL) {
+       if (card->local_node == NULL) {
                spin_unlock_irqrestore(&card->lock, flags);
                goto out_put_card;
        }
-       fw_node_get(local_node);
-       fw_node_get(root_node);
 
        generation = card->generation;
+       root_node = card->root_node;
+       fw_node_get(root_node);
        root_device = root_node->data;
        root_device_is_running = root_device &&
                        atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
        root_device_is_cmc = root_device && root_device->cmc;
-       root_id = root_node->node_id;
-       grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));
+       root_id  = root_node->node_id;
+       irm_id   = card->irm_node->node_id;
+       local_id = card->local_node->node_id;
+
+       grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 8));
 
        if (is_next_generation(generation, card->bm_generation) ||
            (card->bm_generation != generation && grace)) {
@@ -246,16 +261,15 @@ fw_card_bm_work(struct work_struct *work)
                 * next generation.
                 */
 
-               irm_id = card->irm_node->node_id;
                if (!card->irm_node->link_on) {
-                       new_root_id = local_node->node_id;
+                       new_root_id = local_id;
                        fw_notify("IRM has link off, making local node (%02x) root.\n",
                                  new_root_id);
                        goto pick_me;
                }
 
                lock_data[0] = cpu_to_be32(0x3f);
-               lock_data[1] = cpu_to_be32(local_node->node_id);
+               lock_data[1] = cpu_to_be32(local_id);
 
                spin_unlock_irqrestore(&card->lock, flags);
 
@@ -269,9 +283,14 @@ fw_card_bm_work(struct work_struct *work)
                        goto out;
 
                if (rcode == RCODE_COMPLETE &&
-                   lock_data[0] != cpu_to_be32(0x3f))
-                       /* Somebody else is BM, let them do the work. */
+                   lock_data[0] != cpu_to_be32(0x3f)) {
+
+                       /* Somebody else is BM.  Only act as IRM. */
+                       if (local_id == irm_id)
+                               allocate_broadcast_channel(card, generation);
+
                        goto out;
+               }
 
                spin_lock_irqsave(&card->lock, flags);
 
@@ -282,19 +301,18 @@ fw_card_bm_work(struct work_struct *work)
                         * do a bus reset and pick the local node as
                         * root, and thus, IRM.
                         */
-                       new_root_id = local_node->node_id;
+                       new_root_id = local_id;
                        fw_notify("BM lock failed, making local node (%02x) root.\n",
                                  new_root_id);
                        goto pick_me;
                }
        } else if (card->bm_generation != generation) {
                /*
-                * OK, we weren't BM in the last generation, and it's
-                * less than 100ms since last bus reset. Reschedule
-                * this task 100ms from now.
+                * We weren't BM in the last generation, and the last
+                * bus reset is less than 125ms ago.  Reschedule this job.
                 */
                spin_unlock_irqrestore(&card->lock, flags);
-               fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 10));
+               fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 8));
                goto out;
        }
 
@@ -310,7 +328,7 @@ fw_card_bm_work(struct work_struct *work)
                 * Either link_on is false, or we failed to read the
                 * config rom.  In either case, pick another root.
                 */
-               new_root_id = local_node->node_id;
+               new_root_id = local_id;
        } else if (!root_device_is_running) {
                /*
                 * If we haven't probed this device yet, bail out now
@@ -332,7 +350,7 @@ fw_card_bm_work(struct work_struct *work)
                 * successfully read the config rom, but it's not
                 * cycle master capable.
                 */
-               new_root_id = local_node->node_id;
+               new_root_id = local_id;
        }
 
  pick_me:
@@ -363,25 +381,28 @@ fw_card_bm_work(struct work_struct *work)
                          card->index, new_root_id, gap_count);
                fw_send_phy_config(card, new_root_id, generation, gap_count);
                fw_core_initiate_bus_reset(card, 1);
+               /* Will allocate broadcast channel after the reset. */
+       } else {
+               if (local_id == irm_id)
+                       allocate_broadcast_channel(card, generation);
        }
+
  out:
        fw_node_put(root_node);
-       fw_node_put(local_node);
  out_put_card:
        fw_card_put(card);
 }
 
-static void
-flush_timer_callback(unsigned long data)
+static void flush_timer_callback(unsigned long data)
 {
        struct fw_card *card = (struct fw_card *)data;
 
        fw_flush_transactions(card);
 }
 
-void
-fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
-                  struct device *device)
+void fw_card_initialize(struct fw_card *card,
+                       const struct fw_card_driver *driver,
+                       struct device *device)
 {
        static atomic_t index = ATOMIC_INIT(-1);
 
@@ -406,13 +427,12 @@ fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
 }
 EXPORT_SYMBOL(fw_card_initialize);
 
-int
-fw_card_add(struct fw_card *card,
-           u32 max_receive, u32 link_speed, u64 guid)
+int fw_card_add(struct fw_card *card,
+               u32 max_receive, u32 link_speed, u64 guid)
 {
        u32 *config_rom;
        size_t length;
-       int err;
+       int ret;
 
        card->max_receive = max_receive;
        card->link_speed = link_speed;
@@ -423,13 +443,14 @@ fw_card_add(struct fw_card *card,
        list_add_tail(&card->link, &card_list);
        mutex_unlock(&card_mutex);
 
-       err = card->driver->enable(card, config_rom, length);
-       if (err < 0) {
+       ret = card->driver->enable(card, config_rom, length);
+       if (ret < 0) {
                mutex_lock(&card_mutex);
                list_del(&card->link);
                mutex_unlock(&card_mutex);
        }
-       return err;
+
+       return ret;
 }
 EXPORT_SYMBOL(fw_card_add);
 
@@ -442,23 +463,20 @@ EXPORT_SYMBOL(fw_card_add);
  * dummy driver just fails all IO.
  */
 
-static int
-dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
+static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
 {
        BUG();
        return -1;
 }
 
-static int
-dummy_update_phy_reg(struct fw_card *card, int address,
-                    int clear_bits, int set_bits)
+static int dummy_update_phy_reg(struct fw_card *card, int address,
+                               int clear_bits, int set_bits)
 {
        return -ENODEV;
 }
 
-static int
-dummy_set_config_rom(struct fw_card *card,
-                    u32 *config_rom, size_t length)
+static int dummy_set_config_rom(struct fw_card *card,
+                               u32 *config_rom, size_t length)
 {
        /*
         * We take the card out of card_list before setting the dummy
@@ -468,27 +486,23 @@ dummy_set_config_rom(struct fw_card *card,
        return -1;
 }
 
-static void
-dummy_send_request(struct fw_card *card, struct fw_packet *packet)
+static void dummy_send_request(struct fw_card *card, struct fw_packet *packet)
 {
        packet->callback(packet, card, -ENODEV);
 }
 
-static void
-dummy_send_response(struct fw_card *card, struct fw_packet *packet)
+static void dummy_send_response(struct fw_card *card, struct fw_packet *packet)
 {
        packet->callback(packet, card, -ENODEV);
 }
 
-static int
-dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet)
+static int dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet)
 {
        return -ENOENT;
 }
 
-static int
-dummy_enable_phys_dma(struct fw_card *card,
-                     int node_id, int generation)
+static int dummy_enable_phys_dma(struct fw_card *card,
+                                int node_id, int generation)
 {
        return -ENODEV;
 }
@@ -503,16 +517,14 @@ static struct fw_card_driver dummy_driver = {
        .enable_phys_dma = dummy_enable_phys_dma,
 };
 
-void
-fw_card_release(struct kref *kref)
+void fw_card_release(struct kref *kref)
 {
        struct fw_card *card = container_of(kref, struct fw_card, kref);
 
        complete(&card->done);
 }
 
-void
-fw_core_remove_card(struct fw_card *card)
+void fw_core_remove_card(struct fw_card *card)
 {
        card->driver->update_phy_reg(card, 4,
                                     PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
@@ -536,8 +548,7 @@ fw_core_remove_card(struct fw_card *card)
 }
 EXPORT_SYMBOL(fw_core_remove_card);
 
-int
-fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
+int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
 {
        int reg = short_reset ? 5 : 1;
        int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;
index ed03234cbea89ea2247b9d4d005d7e5d1baf1221..7eb6594cc3e5b92e9891773ada1898a4f0831c38 100644 (file)
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
+#include <linux/compat.h>
+#include <linux/delay.h>
 #include <linux/device.h>
-#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/firewire-cdev.h>
+#include <linux/idr.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/poll.h>
 #include <linux/preempt.h>
+#include <linux/spinlock.h>
 #include <linux/time.h>
-#include <linux/delay.h>
-#include <linux/mm.h>
-#include <linux/idr.h>
-#include <linux/compat.h>
-#include <linux/firewire-cdev.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include "fw-transaction.h"
-#include "fw-topology.h"
+
 #include "fw-device.h"
+#include "fw-topology.h"
+#include "fw-transaction.h"
+
+struct client {
+       u32 version;
+       struct fw_device *device;
+
+       spinlock_t lock;
+       bool in_shutdown;
+       struct idr resource_idr;
+       struct list_head event_list;
+       wait_queue_head_t wait;
+       u64 bus_reset_closure;
+
+       struct fw_iso_context *iso_context;
+       u64 iso_closure;
+       struct fw_iso_buffer buffer;
+       unsigned long vm_start;
 
-struct client;
-struct client_resource {
        struct list_head link;
-       void (*release)(struct client *client, struct client_resource *r);
-       u32 handle;
+       struct kref kref;
 };
 
+static inline void client_get(struct client *client)
+{
+       kref_get(&client->kref);
+}
+
+static void client_release(struct kref *kref)
+{
+       struct client *client = container_of(kref, struct client, kref);
+
+       fw_device_put(client->device);
+       kfree(client);
+}
+
+static void client_put(struct client *client)
+{
+       kref_put(&client->kref, client_release);
+}
+
+struct client_resource;
+typedef void (*client_resource_release_fn_t)(struct client *,
+                                            struct client_resource *);
+struct client_resource {
+       client_resource_release_fn_t release;
+       int handle;
+};
+
+struct address_handler_resource {
+       struct client_resource resource;
+       struct fw_address_handler handler;
+       __u64 closure;
+       struct client *client;
+};
+
+struct outbound_transaction_resource {
+       struct client_resource resource;
+       struct fw_transaction transaction;
+};
+
+struct inbound_transaction_resource {
+       struct client_resource resource;
+       struct fw_request *request;
+       void *data;
+       size_t length;
+};
+
+struct descriptor_resource {
+       struct client_resource resource;
+       struct fw_descriptor descriptor;
+       u32 data[0];
+};
+
+struct iso_resource {
+       struct client_resource resource;
+       struct client *client;
+       /* Schedule work and access todo only with client->lock held. */
+       struct delayed_work work;
+       enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC,
+             ISO_RES_ALLOC_ONCE, ISO_RES_DEALLOC_ONCE,} todo;
+       int generation;
+       u64 channels;
+       s32 bandwidth;
+       struct iso_resource_event *e_alloc, *e_dealloc;
+};
+
+static void schedule_iso_resource(struct iso_resource *);
+static void release_iso_resource(struct client *, struct client_resource *);
+
 /*
  * dequeue_event() just kfree()'s the event, so the event has to be
- * the first field in the struct.
+ * the first field in a struct XYZ_event.
  */
-
 struct event {
        struct { void *data; size_t size; } v[2];
        struct list_head link;
 };
 
-struct bus_reset {
+struct bus_reset_event {
        struct event event;
        struct fw_cdev_event_bus_reset reset;
 };
 
-struct response {
+struct outbound_transaction_event {
        struct event event;
-       struct fw_transaction transaction;
        struct client *client;
-       struct client_resource resource;
+       struct outbound_transaction_resource r;
        struct fw_cdev_event_response response;
 };
 
-struct iso_interrupt {
+struct inbound_transaction_event {
        struct event event;
-       struct fw_cdev_event_iso_interrupt interrupt;
+       struct fw_cdev_event_request request;
 };
 
-struct client {
-       u32 version;
-       struct fw_device *device;
-       spinlock_t lock;
-       u32 resource_handle;
-       struct list_head resource_list;
-       struct list_head event_list;
-       wait_queue_head_t wait;
-       u64 bus_reset_closure;
-
-       struct fw_iso_context *iso_context;
-       u64 iso_closure;
-       struct fw_iso_buffer buffer;
-       unsigned long vm_start;
+struct iso_interrupt_event {
+       struct event event;
+       struct fw_cdev_event_iso_interrupt interrupt;
+};
 
-       struct list_head link;
+struct iso_resource_event {
+       struct event event;
+       struct fw_cdev_event_iso_resource resource;
 };
 
-static inline void __user *
-u64_to_uptr(__u64 value)
+static inline void __user *u64_to_uptr(__u64 value)
 {
        return (void __user *)(unsigned long)value;
 }
 
-static inline __u64
-uptr_to_u64(void __user *ptr)
+static inline __u64 uptr_to_u64(void __user *ptr)
 {
        return (__u64)(unsigned long)ptr;
 }
@@ -107,7 +182,6 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
 {
        struct fw_device *device;
        struct client *client;
-       unsigned long flags;
 
        device = fw_device_get_by_devt(inode->i_rdev);
        if (device == NULL)
@@ -125,16 +199,17 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
        }
 
        client->device = device;
-       INIT_LIST_HEAD(&client->event_list);
-       INIT_LIST_HEAD(&client->resource_list);
        spin_lock_init(&client->lock);
+       idr_init(&client->resource_idr);
+       INIT_LIST_HEAD(&client->event_list);
        init_waitqueue_head(&client->wait);
+       kref_init(&client->kref);
 
        file->private_data = client;
 
-       spin_lock_irqsave(&device->card->lock, flags);
+       mutex_lock(&device->client_list_mutex);
        list_add_tail(&client->link, &device->client_list);
-       spin_unlock_irqrestore(&device->card->lock, flags);
+       mutex_unlock(&device->client_list_mutex);
 
        return 0;
 }
@@ -150,68 +225,69 @@ static void queue_event(struct client *client, struct event *event,
        event->v[1].size = size1;
 
        spin_lock_irqsave(&client->lock, flags);
-       list_add_tail(&event->link, &client->event_list);
+       if (client->in_shutdown)
+               kfree(event);
+       else
+               list_add_tail(&event->link, &client->event_list);
        spin_unlock_irqrestore(&client->lock, flags);
 
        wake_up_interruptible(&client->wait);
 }
 
-static int
-dequeue_event(struct client *client, char __user *buffer, size_t count)
+static int dequeue_event(struct client *client,
+                        char __user *buffer, size_t count)
 {
-       unsigned long flags;
        struct event *event;
        size_t size, total;
-       int i, retval;
+       int i, ret;
 
-       retval = wait_event_interruptible(client->wait,
-                                         !list_empty(&client->event_list) ||
-                                         fw_device_is_shutdown(client->device));
-       if (retval < 0)
-               return retval;
+       ret = wait_event_interruptible(client->wait,
+                       !list_empty(&client->event_list) ||
+                       fw_device_is_shutdown(client->device));
+       if (ret < 0)
+               return ret;
 
        if (list_empty(&client->event_list) &&
                       fw_device_is_shutdown(client->device))
                return -ENODEV;
 
-       spin_lock_irqsave(&client->lock, flags);
-       event = container_of(client->event_list.next, struct event, link);
+       spin_lock_irq(&client->lock);
+       event = list_first_entry(&client->event_list, struct event, link);
        list_del(&event->link);
-       spin_unlock_irqrestore(&client->lock, flags);
+       spin_unlock_irq(&client->lock);
 
        total = 0;
        for (i = 0; i < ARRAY_SIZE(event->v) && total < count; i++) {
                size = min(event->v[i].size, count - total);
                if (copy_to_user(buffer + total, event->v[i].data, size)) {
-                       retval = -EFAULT;
+                       ret = -EFAULT;
                        goto out;
                }
                total += size;
        }
-       retval = total;
+       ret = total;
 
  out:
        kfree(event);
 
-       return retval;
+       return ret;
 }
 
-static ssize_t
-fw_device_op_read(struct file *file,
-                 char __user *buffer, size_t count, loff_t *offset)
+static ssize_t fw_device_op_read(struct file *file, char __user *buffer,
+                                size_t count, loff_t *offset)
 {
        struct client *client = file->private_data;
 
        return dequeue_event(client, buffer, count);
 }
 
-/* caller must hold card->lock so that node pointers can be dereferenced here */
-static void
-fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
-                    struct client *client)
+static void fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
+                                struct client *client)
 {
        struct fw_card *card = client->device->card;
 
+       spin_lock_irq(&card->lock);
+
        event->closure       = client->bus_reset_closure;
        event->type          = FW_CDEV_EVENT_BUS_RESET;
        event->generation    = client->device->generation;
@@ -220,39 +296,49 @@ fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
        event->bm_node_id    = 0; /* FIXME: We don't track the BM. */
        event->irm_node_id   = card->irm_node->node_id;
        event->root_node_id  = card->root_node->node_id;
+
+       spin_unlock_irq(&card->lock);
 }
 
-static void
-for_each_client(struct fw_device *device,
-               void (*callback)(struct client *client))
+static void for_each_client(struct fw_device *device,
+                           void (*callback)(struct client *client))
 {
-       struct fw_card *card = device->card;
        struct client *c;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
 
+       mutex_lock(&device->client_list_mutex);
        list_for_each_entry(c, &device->client_list, link)
                callback(c);
+       mutex_unlock(&device->client_list_mutex);
+}
+
+static int schedule_reallocations(int id, void *p, void *data)
+{
+       struct client_resource *r = p;
 
-       spin_unlock_irqrestore(&card->lock, flags);
+       if (r->release == release_iso_resource)
+               schedule_iso_resource(container_of(r,
+                                       struct iso_resource, resource));
+       return 0;
 }
 
-static void
-queue_bus_reset_event(struct client *client)
+static void queue_bus_reset_event(struct client *client)
 {
-       struct bus_reset *bus_reset;
+       struct bus_reset_event *e;
 
-       bus_reset = kzalloc(sizeof(*bus_reset), GFP_ATOMIC);
-       if (bus_reset == NULL) {
+       e = kzalloc(sizeof(*e), GFP_KERNEL);
+       if (e == NULL) {
                fw_notify("Out of memory when allocating bus reset event\n");
                return;
        }
 
-       fill_bus_reset_event(&bus_reset->reset, client);
+       fill_bus_reset_event(&e->reset, client);
+
+       queue_event(client, &e->event,
+                   &e->reset, sizeof(e->reset), NULL, 0);
 
-       queue_event(client, &bus_reset->event,
-                   &bus_reset->reset, sizeof(bus_reset->reset), NULL, 0);
+       spin_lock_irq(&client->lock);
+       idr_for_each(&client->resource_idr, schedule_reallocations, client);
+       spin_unlock_irq(&client->lock);
 }
 
 void fw_device_cdev_update(struct fw_device *device)
@@ -274,11 +360,11 @@ static int ioctl_get_info(struct client *client, void *buffer)
 {
        struct fw_cdev_get_info *get_info = buffer;
        struct fw_cdev_event_bus_reset bus_reset;
-       struct fw_card *card = client->device->card;
        unsigned long ret = 0;
 
        client->version = get_info->version;
        get_info->version = FW_CDEV_VERSION;
+       get_info->card = client->device->card->index;
 
        down_read(&fw_device_rwsem);
 
@@ -300,49 +386,61 @@ static int ioctl_get_info(struct client *client, void *buffer)
        client->bus_reset_closure = get_info->bus_reset_closure;
        if (get_info->bus_reset != 0) {
                void __user *uptr = u64_to_uptr(get_info->bus_reset);
-               unsigned long flags;
 
-               spin_lock_irqsave(&card->lock, flags);
                fill_bus_reset_event(&bus_reset, client);
-               spin_unlock_irqrestore(&card->lock, flags);
-
                if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
                        return -EFAULT;
        }
 
-       get_info->card = card->index;
-
        return 0;
 }
 
-static void
-add_client_resource(struct client *client, struct client_resource *resource)
+static int add_client_resource(struct client *client,
+                              struct client_resource *resource, gfp_t gfp_mask)
 {
        unsigned long flags;
+       int ret;
+
+ retry:
+       if (idr_pre_get(&client->resource_idr, gfp_mask) == 0)
+               return -ENOMEM;
 
        spin_lock_irqsave(&client->lock, flags);
-       list_add_tail(&resource->link, &client->resource_list);
-       resource->handle = client->resource_handle++;
+       if (client->in_shutdown)
+               ret = -ECANCELED;
+       else
+               ret = idr_get_new(&client->resource_idr, resource,
+                                 &resource->handle);
+       if (ret >= 0) {
+               client_get(client);
+               if (resource->release == release_iso_resource)
+                       schedule_iso_resource(container_of(resource,
+                                               struct iso_resource, resource));
+       }
        spin_unlock_irqrestore(&client->lock, flags);
+
+       if (ret == -EAGAIN)
+               goto retry;
+
+       return ret < 0 ? ret : 0;
 }
 
-static int
-release_client_resource(struct client *client, u32 handle,
-                       struct client_resource **resource)
+static int release_client_resource(struct client *client, u32 handle,
+                                  client_resource_release_fn_t release,
+                                  struct client_resource **resource)
 {
        struct client_resource *r;
-       unsigned long flags;
 
-       spin_lock_irqsave(&client->lock, flags);
-       list_for_each_entry(r, &client->resource_list, link) {
-               if (r->handle == handle) {
-                       list_del(&r->link);
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&client->lock, flags);
+       spin_lock_irq(&client->lock);
+       if (client->in_shutdown)
+               r = NULL;
+       else
+               r = idr_find(&client->resource_idr, handle);
+       if (r && r->release == release)
+               idr_remove(&client->resource_idr, handle);
+       spin_unlock_irq(&client->lock);
 
-       if (&r->link == &client->resource_list)
+       if (!(r && r->release == release))
                return -EINVAL;
 
        if (resource)
@@ -350,203 +448,239 @@ release_client_resource(struct client *client, u32 handle,
        else
                r->release(client, r);
 
+       client_put(client);
+
        return 0;
 }
 
-static void
-release_transaction(struct client *client, struct client_resource *resource)
+static void release_transaction(struct client *client,
+                               struct client_resource *resource)
 {
-       struct response *response =
-               container_of(resource, struct response, resource);
+       struct outbound_transaction_resource *r = container_of(resource,
+                       struct outbound_transaction_resource, resource);
 
-       fw_cancel_transaction(client->device->card, &response->transaction);
+       fw_cancel_transaction(client->device->card, &r->transaction);
 }
 
-static void
-complete_transaction(struct fw_card *card, int rcode,
-                    void *payload, size_t length, void *data)
+static void complete_transaction(struct fw_card *card, int rcode,
+                                void *payload, size_t length, void *data)
 {
-       struct response *response = data;
-       struct client *client = response->client;
+       struct outbound_transaction_event *e = data;
+       struct fw_cdev_event_response *rsp = &e->response;
+       struct client *client = e->client;
        unsigned long flags;
-       struct fw_cdev_event_response *r = &response->response;
 
-       if (length < r->length)
-               r->length = length;
+       if (length < rsp->length)
+               rsp->length = length;
        if (rcode == RCODE_COMPLETE)
-               memcpy(r->data, payload, r->length);
+               memcpy(rsp->data, payload, rsp->length);
 
        spin_lock_irqsave(&client->lock, flags);
-       list_del(&response->resource.link);
+       /*
+        * 1. If called while in shutdown, the idr tree must be left untouched.
+        *    The idr handle will be removed and the client reference will be
+        *    dropped later.
+        * 2. If the call chain was release_client_resource ->
+        *    release_transaction -> complete_transaction (instead of a normal
+        *    conclusion of the transaction), i.e. if this resource was already
+        *    unregistered from the idr, the client reference will be dropped
+        *    by release_client_resource and we must not drop it here.
+        */
+       if (!client->in_shutdown &&
+           idr_find(&client->resource_idr, e->r.resource.handle)) {
+               idr_remove(&client->resource_idr, e->r.resource.handle);
+               /* Drop the idr's reference */
+               client_put(client);
+       }
        spin_unlock_irqrestore(&client->lock, flags);
 
-       r->type   = FW_CDEV_EVENT_RESPONSE;
-       r->rcode  = rcode;
+       rsp->type = FW_CDEV_EVENT_RESPONSE;
+       rsp->rcode = rcode;
 
        /*
-        * In the case that sizeof(*r) doesn't align with the position of the
+        * In the case that sizeof(*rsp) doesn't align with the position of the
         * data, and the read is short, preserve an extra copy of the data
         * to stay compatible with a pre-2.6.27 bug.  Since the bug is harmless
         * for short reads and some apps depended on it, this is both safe
         * and prudent for compatibility.
         */
-       if (r->length <= sizeof(*r) - offsetof(typeof(*r), data))
-               queue_event(client, &response->event, r, sizeof(*r),
-                           r->data, r->length);
+       if (rsp->length <= sizeof(*rsp) - offsetof(typeof(*rsp), data))
+               queue_event(client, &e->event, rsp, sizeof(*rsp),
+                           rsp->data, rsp->length);
        else
-               queue_event(client, &response->event, r, sizeof(*r) + r->length,
+               queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length,
                            NULL, 0);
+
+       /* Drop the transaction callback's reference */
+       client_put(client);
 }
 
-static int ioctl_send_request(struct client *client, void *buffer)
+static int init_request(struct client *client,
+                       struct fw_cdev_send_request *request,
+                       int destination_id, int speed)
 {
-       struct fw_device *device = client->device;
-       struct fw_cdev_send_request *request = buffer;
-       struct response *response;
+       struct outbound_transaction_event *e;
+       int ret;
 
-       /* What is the biggest size we'll accept, really? */
-       if (request->length > 4096)
-               return -EINVAL;
+       if (request->tcode != TCODE_STREAM_DATA &&
+           (request->length > 4096 || request->length > 512 << speed))
+               return -EIO;
 
-       response = kmalloc(sizeof(*response) + request->length, GFP_KERNEL);
-       if (response == NULL)
+       e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL);
+       if (e == NULL)
                return -ENOMEM;
 
-       response->client = client;
-       response->response.length = request->length;
-       response->response.closure = request->closure;
+       e->client = client;
+       e->response.length = request->length;
+       e->response.closure = request->closure;
 
        if (request->data &&
-           copy_from_user(response->response.data,
+           copy_from_user(e->response.data,
                           u64_to_uptr(request->data), request->length)) {
-               kfree(response);
-               return -EFAULT;
+               ret = -EFAULT;
+               goto failed;
        }
 
-       response->resource.release = release_transaction;
-       add_client_resource(client, &response->resource);
+       e->r.resource.release = release_transaction;
+       ret = add_client_resource(client, &e->r.resource, GFP_KERNEL);
+       if (ret < 0)
+               goto failed;
 
-       fw_send_request(device->card, &response->transaction,
-                       request->tcode & 0x1f,
-                       device->node->node_id,
-                       request->generation,
-                       device->max_speed,
-                       request->offset,
-                       response->response.data, request->length,
-                       complete_transaction, response);
+       /* Get a reference for the transaction callback */
+       client_get(client);
 
-       if (request->data)
-               return sizeof(request) + request->length;
-       else
-               return sizeof(request);
+       fw_send_request(client->device->card, &e->r.transaction,
+                       request->tcode, destination_id, request->generation,
+                       speed, request->offset, e->response.data,
+                       request->length, complete_transaction, e);
+       return 0;
+
+ failed:
+       kfree(e);
+
+       return ret;
 }
 
-struct address_handler {
-       struct fw_address_handler handler;
-       __u64 closure;
-       struct client *client;
-       struct client_resource resource;
-};
+static int ioctl_send_request(struct client *client, void *buffer)
+{
+       struct fw_cdev_send_request *request = buffer;
 
-struct request {
-       struct fw_request *request;
-       void *data;
-       size_t length;
-       struct client_resource resource;
-};
+       switch (request->tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+       case TCODE_WRITE_BLOCK_REQUEST:
+       case TCODE_READ_QUADLET_REQUEST:
+       case TCODE_READ_BLOCK_REQUEST:
+       case TCODE_LOCK_MASK_SWAP:
+       case TCODE_LOCK_COMPARE_SWAP:
+       case TCODE_LOCK_FETCH_ADD:
+       case TCODE_LOCK_LITTLE_ADD:
+       case TCODE_LOCK_BOUNDED_ADD:
+       case TCODE_LOCK_WRAP_ADD:
+       case TCODE_LOCK_VENDOR_DEPENDENT:
+               break;
+       default:
+               return -EINVAL;
+       }
 
-struct request_event {
-       struct event event;
-       struct fw_cdev_event_request request;
-};
+       return init_request(client, request, client->device->node_id,
+                           client->device->max_speed);
+}
 
-static void
-release_request(struct client *client, struct client_resource *resource)
+static void release_request(struct client *client,
+                           struct client_resource *resource)
 {
-       struct request *request =
-               container_of(resource, struct request, resource);
+       struct inbound_transaction_resource *r = container_of(resource,
+                       struct inbound_transaction_resource, resource);
 
-       fw_send_response(client->device->card, request->request,
+       fw_send_response(client->device->card, r->request,
                         RCODE_CONFLICT_ERROR);
-       kfree(request);
+       kfree(r);
 }
 
-static void
-handle_request(struct fw_card *card, struct fw_request *r,
-              int tcode, int destination, int source,
-              int generation, int speed,
-              unsigned long long offset,
-              void *payload, size_t length, void *callback_data)
+static void handle_request(struct fw_card *card, struct fw_request *request,
+                          int tcode, int destination, int source,
+                          int generation, int speed,
+                          unsigned long long offset,
+                          void *payload, size_t length, void *callback_data)
 {
-       struct address_handler *handler = callback_data;
-       struct request *request;
-       struct request_event *e;
-       struct client *client = handler->client;
+       struct address_handler_resource *handler = callback_data;
+       struct inbound_transaction_resource *r;
+       struct inbound_transaction_event *e;
+       int ret;
 
-       request = kmalloc(sizeof(*request), GFP_ATOMIC);
+       r = kmalloc(sizeof(*r), GFP_ATOMIC);
        e = kmalloc(sizeof(*e), GFP_ATOMIC);
-       if (request == NULL || e == NULL) {
-               kfree(request);
-               kfree(e);
-               fw_send_response(card, r, RCODE_CONFLICT_ERROR);
-               return;
-       }
+       if (r == NULL || e == NULL)
+               goto failed;
 
-       request->request = r;
-       request->data    = payload;
-       request->length  = length;
+       r->request = request;
+       r->data    = payload;
+       r->length  = length;
 
-       request->resource.release = release_request;
-       add_client_resource(client, &request->resource);
+       r->resource.release = release_request;
+       ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
+       if (ret < 0)
+               goto failed;
 
        e->request.type    = FW_CDEV_EVENT_REQUEST;
        e->request.tcode   = tcode;
        e->request.offset  = offset;
        e->request.length  = length;
-       e->request.handle  = request->resource.handle;
+       e->request.handle  = r->resource.handle;
        e->request.closure = handler->closure;
 
-       queue_event(client, &e->event,
+       queue_event(handler->client, &e->event,
                    &e->request, sizeof(e->request), payload, length);
+       return;
+
+ failed:
+       kfree(r);
+       kfree(e);
+       fw_send_response(card, request, RCODE_CONFLICT_ERROR);
 }
 
-static void
-release_address_handler(struct client *client,
-                       struct client_resource *resource)
+static void release_address_handler(struct client *client,
+                                   struct client_resource *resource)
 {
-       struct address_handler *handler =
-               container_of(resource, struct address_handler, resource);
+       struct address_handler_resource *r =
+           container_of(resource, struct address_handler_resource, resource);
 
-       fw_core_remove_address_handler(&handler->handler);
-       kfree(handler);
+       fw_core_remove_address_handler(&r->handler);
+       kfree(r);
 }
 
 static int ioctl_allocate(struct client *client, void *buffer)
 {
        struct fw_cdev_allocate *request = buffer;
-       struct address_handler *handler;
+       struct address_handler_resource *r;
        struct fw_address_region region;
+       int ret;
 
-       handler = kmalloc(sizeof(*handler), GFP_KERNEL);
-       if (handler == NULL)
+       r = kmalloc(sizeof(*r), GFP_KERNEL);
+       if (r == NULL)
                return -ENOMEM;
 
        region.start = request->offset;
        region.end = request->offset + request->length;
-       handler->handler.length = request->length;
-       handler->handler.address_callback = handle_request;
-       handler->handler.callback_data = handler;
-       handler->closure = request->closure;
-       handler->client = client;
-
-       if (fw_core_add_address_handler(&handler->handler, &region) < 0) {
-               kfree(handler);
-               return -EBUSY;
+       r->handler.length = request->length;
+       r->handler.address_callback = handle_request;
+       r->handler.callback_data = r;
+       r->closure = request->closure;
+       r->client = client;
+
+       ret = fw_core_add_address_handler(&r->handler, &region);
+       if (ret < 0) {
+               kfree(r);
+               return ret;
        }
 
-       handler->resource.release = release_address_handler;
-       add_client_resource(client, &handler->resource);
-       request->handle = handler->resource.handle;
+       r->resource.release = release_address_handler;
+       ret = add_client_resource(client, &r->resource, GFP_KERNEL);
+       if (ret < 0) {
+               release_address_handler(client, &r->resource);
+               return ret;
+       }
+       request->handle = r->resource.handle;
 
        return 0;
 }
@@ -555,18 +689,22 @@ static int ioctl_deallocate(struct client *client, void *buffer)
 {
        struct fw_cdev_deallocate *request = buffer;
 
-       return release_client_resource(client, request->handle, NULL);
+       return release_client_resource(client, request->handle,
+                                      release_address_handler, NULL);
 }
 
 static int ioctl_send_response(struct client *client, void *buffer)
 {
        struct fw_cdev_send_response *request = buffer;
        struct client_resource *resource;
-       struct request *r;
+       struct inbound_transaction_resource *r;
 
-       if (release_client_resource(client, request->handle, &resource) < 0)
+       if (release_client_resource(client, request->handle,
+                                   release_request, &resource) < 0)
                return -EINVAL;
-       r = container_of(resource, struct request, resource);
+
+       r = container_of(resource, struct inbound_transaction_resource,
+                        resource);
        if (request->length < r->length)
                r->length = request->length;
        if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
@@ -588,85 +726,92 @@ static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
        return fw_core_initiate_bus_reset(client->device->card, short_reset);
 }
 
-struct descriptor {
-       struct fw_descriptor d;
-       struct client_resource resource;
-       u32 data[0];
-};
-
 static void release_descriptor(struct client *client,
                               struct client_resource *resource)
 {
-       struct descriptor *descriptor =
-               container_of(resource, struct descriptor, resource);
+       struct descriptor_resource *r =
+               container_of(resource, struct descriptor_resource, resource);
 
-       fw_core_remove_descriptor(&descriptor->d);
-       kfree(descriptor);
+       fw_core_remove_descriptor(&r->descriptor);
+       kfree(r);
 }
 
 static int ioctl_add_descriptor(struct client *client, void *buffer)
 {
        struct fw_cdev_add_descriptor *request = buffer;
-       struct descriptor *descriptor;
-       int retval;
+       struct fw_card *card = client->device->card;
+       struct descriptor_resource *r;
+       int ret;
+
+       /* Access policy: Allow this ioctl only on local nodes' device files. */
+       spin_lock_irq(&card->lock);
+       ret = client->device->node_id != card->local_node->node_id;
+       spin_unlock_irq(&card->lock);
+       if (ret)
+               return -ENOSYS;
 
        if (request->length > 256)
                return -EINVAL;
 
-       descriptor =
-               kmalloc(sizeof(*descriptor) + request->length * 4, GFP_KERNEL);
-       if (descriptor == NULL)
+       r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL);
+       if (r == NULL)
                return -ENOMEM;
 
-       if (copy_from_user(descriptor->data,
+       if (copy_from_user(r->data,
                           u64_to_uptr(request->data), request->length * 4)) {
-               kfree(descriptor);
-               return -EFAULT;
+               ret = -EFAULT;
+               goto failed;
        }
 
-       descriptor->d.length = request->length;
-       descriptor->d.immediate = request->immediate;
-       descriptor->d.key = request->key;
-       descriptor->d.data = descriptor->data;
+       r->descriptor.length    = request->length;
+       r->descriptor.immediate = request->immediate;
+       r->descriptor.key       = request->key;
+       r->descriptor.data      = r->data;
 
-       retval = fw_core_add_descriptor(&descriptor->d);
-       if (retval < 0) {
-               kfree(descriptor);
-               return retval;
-       }
+       ret = fw_core_add_descriptor(&r->descriptor);
+       if (ret < 0)
+               goto failed;
 
-       descriptor->resource.release = release_descriptor;
-       add_client_resource(client, &descriptor->resource);
-       request->handle = descriptor->resource.handle;
+       r->resource.release = release_descriptor;
+       ret = add_client_resource(client, &r->resource, GFP_KERNEL);
+       if (ret < 0) {
+               fw_core_remove_descriptor(&r->descriptor);
+               goto failed;
+       }
+       request->handle = r->resource.handle;
 
        return 0;
+ failed:
+       kfree(r);
+
+       return ret;
 }
 
 static int ioctl_remove_descriptor(struct client *client, void *buffer)
 {
        struct fw_cdev_remove_descriptor *request = buffer;
 
-       return release_client_resource(client, request->handle, NULL);
+       return release_client_resource(client, request->handle,
+                                      release_descriptor, NULL);
 }
 
-static void
-iso_callback(struct fw_iso_context *context, u32 cycle,
-            size_t header_length, void *header, void *data)
+static void iso_callback(struct fw_iso_context *context, u32 cycle,
+                        size_t header_length, void *header, void *data)
 {
        struct client *client = data;
-       struct iso_interrupt *irq;
+       struct iso_interrupt_event *e;
 
-       irq = kzalloc(sizeof(*irq) + header_length, GFP_ATOMIC);
-       if (irq == NULL)
+       e = kzalloc(sizeof(*e) + header_length, GFP_ATOMIC);
+       if (e == NULL)
                return;
 
-       irq->interrupt.type      = FW_CDEV_EVENT_ISO_INTERRUPT;
-       irq->interrupt.closure   = client->iso_closure;
-       irq->interrupt.cycle     = cycle;
-       irq->interrupt.header_length = header_length;
-       memcpy(irq->interrupt.header, header, header_length);
-       queue_event(client, &irq->event, &irq->interrupt,
-                   sizeof(irq->interrupt) + header_length, NULL, 0);
+       e->interrupt.type      = FW_CDEV_EVENT_ISO_INTERRUPT;
+       e->interrupt.closure   = client->iso_closure;
+       e->interrupt.cycle     = cycle;
+       e->interrupt.header_length = header_length;
+       memcpy(e->interrupt.header, header, header_length);
+       queue_event(client, &e->event, &e->interrupt,
+                   sizeof(e->interrupt) + header_length, NULL, 0);
 }
 
 static int ioctl_create_iso_context(struct client *client, void *buffer)
@@ -871,6 +1016,261 @@ static int ioctl_get_cycle_timer(struct client *client, void *buffer)
        return 0;
 }
 
+static void iso_resource_work(struct work_struct *work)
+{
+       struct iso_resource_event *e;
+       struct iso_resource *r =
+                       container_of(work, struct iso_resource, work.work);
+       struct client *client = r->client;
+       int generation, channel, bandwidth, todo;
+       bool skip, free, success;
+
+       spin_lock_irq(&client->lock);
+       generation = client->device->generation;
+       todo = r->todo;
+       /* Allow 1000ms grace period for other reallocations. */
+       if (todo == ISO_RES_ALLOC &&
+           time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) {
+               if (schedule_delayed_work(&r->work, DIV_ROUND_UP(HZ, 3)))
+                       client_get(client);
+               skip = true;
+       } else {
+               /* We could be called twice within the same generation. */
+               skip = todo == ISO_RES_REALLOC &&
+                      r->generation == generation;
+       }
+       free = todo == ISO_RES_DEALLOC ||
+              todo == ISO_RES_ALLOC_ONCE ||
+              todo == ISO_RES_DEALLOC_ONCE;
+       r->generation = generation;
+       spin_unlock_irq(&client->lock);
+
+       if (skip)
+               goto out;
+
+       bandwidth = r->bandwidth;
+
+       fw_iso_resource_manage(client->device->card, generation,
+                       r->channels, &channel, &bandwidth,
+                       todo == ISO_RES_ALLOC ||
+                       todo == ISO_RES_REALLOC ||
+                       todo == ISO_RES_ALLOC_ONCE);
+       /*
+        * Is this generation outdated already?  As long as this resource sticks
+        * in the idr, it will be scheduled again for a newer generation or at
+        * shutdown.
+        */
+       if (channel == -EAGAIN &&
+           (todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC))
+               goto out;
+
+       success = channel >= 0 || bandwidth > 0;
+
+       spin_lock_irq(&client->lock);
+       /*
+        * Transit from allocation to reallocation, except if the client
+        * requested deallocation in the meantime.
+        */
+       if (r->todo == ISO_RES_ALLOC)
+               r->todo = ISO_RES_REALLOC;
+       /*
+        * Allocation or reallocation failure?  Pull this resource out of the
+        * idr and prepare for deletion, unless the client is shutting down.
+        */
+       if (r->todo == ISO_RES_REALLOC && !success &&
+           !client->in_shutdown &&
+           idr_find(&client->resource_idr, r->resource.handle)) {
+               idr_remove(&client->resource_idr, r->resource.handle);
+               client_put(client);
+               free = true;
+       }
+       spin_unlock_irq(&client->lock);
+
+       if (todo == ISO_RES_ALLOC && channel >= 0)
+               r->channels = 1ULL << channel;
+
+       if (todo == ISO_RES_REALLOC && success)
+               goto out;
+
+       if (todo == ISO_RES_ALLOC || todo == ISO_RES_ALLOC_ONCE) {
+               e = r->e_alloc;
+               r->e_alloc = NULL;
+       } else {
+               e = r->e_dealloc;
+               r->e_dealloc = NULL;
+       }
+       e->resource.handle      = r->resource.handle;
+       e->resource.channel     = channel;
+       e->resource.bandwidth   = bandwidth;
+
+       queue_event(client, &e->event,
+                   &e->resource, sizeof(e->resource), NULL, 0);
+
+       if (free) {
+               cancel_delayed_work(&r->work);
+               kfree(r->e_alloc);
+               kfree(r->e_dealloc);
+               kfree(r);
+       }
+ out:
+       client_put(client);
+}
+
+static void schedule_iso_resource(struct iso_resource *r)
+{
+       client_get(r->client);
+       if (!schedule_delayed_work(&r->work, 0))
+               client_put(r->client);
+}
+
+static void release_iso_resource(struct client *client,
+                                struct client_resource *resource)
+{
+       struct iso_resource *r =
+               container_of(resource, struct iso_resource, resource);
+
+       spin_lock_irq(&client->lock);
+       r->todo = ISO_RES_DEALLOC;
+       schedule_iso_resource(r);
+       spin_unlock_irq(&client->lock);
+}
+
+static int init_iso_resource(struct client *client,
+               struct fw_cdev_allocate_iso_resource *request, int todo)
+{
+       struct iso_resource_event *e1, *e2;
+       struct iso_resource *r;
+       int ret;
+
+       if ((request->channels == 0 && request->bandwidth == 0) ||
+           request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL ||
+           request->bandwidth < 0)
+               return -EINVAL;
+
+       r  = kmalloc(sizeof(*r), GFP_KERNEL);
+       e1 = kmalloc(sizeof(*e1), GFP_KERNEL);
+       e2 = kmalloc(sizeof(*e2), GFP_KERNEL);
+       if (r == NULL || e1 == NULL || e2 == NULL) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       INIT_DELAYED_WORK(&r->work, iso_resource_work);
+       r->client       = client;
+       r->todo         = todo;
+       r->generation   = -1;
+       r->channels     = request->channels;
+       r->bandwidth    = request->bandwidth;
+       r->e_alloc      = e1;
+       r->e_dealloc    = e2;
+
+       e1->resource.closure    = request->closure;
+       e1->resource.type       = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
+       e2->resource.closure    = request->closure;
+       e2->resource.type       = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
+
+       if (todo == ISO_RES_ALLOC) {
+               r->resource.release = release_iso_resource;
+               ret = add_client_resource(client, &r->resource, GFP_KERNEL);
+               if (ret < 0)
+                       goto fail;
+       } else {
+               r->resource.release = NULL;
+               r->resource.handle = -1;
+               schedule_iso_resource(r);
+       }
+       request->handle = r->resource.handle;
+
+       return 0;
+ fail:
+       kfree(r);
+       kfree(e1);
+       kfree(e2);
+
+       return ret;
+}
+
+static int ioctl_allocate_iso_resource(struct client *client, void *buffer)
+{
+       struct fw_cdev_allocate_iso_resource *request = buffer;
+
+       return init_iso_resource(client, request, ISO_RES_ALLOC);
+}
+
+static int ioctl_deallocate_iso_resource(struct client *client, void *buffer)
+{
+       struct fw_cdev_deallocate *request = buffer;
+
+       return release_client_resource(client, request->handle,
+                                      release_iso_resource, NULL);
+}
+
+static int ioctl_allocate_iso_resource_once(struct client *client, void *buffer)
+{
+       struct fw_cdev_allocate_iso_resource *request = buffer;
+
+       return init_iso_resource(client, request, ISO_RES_ALLOC_ONCE);
+}
+
+static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffer)
+{
+       struct fw_cdev_allocate_iso_resource *request = buffer;
+
+       return init_iso_resource(client, request, ISO_RES_DEALLOC_ONCE);
+}
+
+/*
+ * Returns a speed code:  Maximum speed to or from this device,
+ * limited by the device's link speed, the local node's link speed,
+ * and all PHY port speeds between the two links.
+ */
+static int ioctl_get_speed(struct client *client, void *buffer)
+{
+       return client->device->max_speed;
+}
+
+static int ioctl_send_broadcast_request(struct client *client, void *buffer)
+{
+       struct fw_cdev_send_request *request = buffer;
+
+       switch (request->tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+       case TCODE_WRITE_BLOCK_REQUEST:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Security policy: Only allow accesses to Units Space. */
+       if (request->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END)
+               return -EACCES;
+
+       return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100);
+}
+
+static int ioctl_send_stream_packet(struct client *client, void *buffer)
+{
+       struct fw_cdev_send_stream_packet *p = buffer;
+       struct fw_cdev_send_request request;
+       int dest;
+
+       if (p->speed > client->device->card->link_speed ||
+           p->length > 1024 << p->speed)
+               return -EIO;
+
+       if (p->tag > 3 || p->channel > 63 || p->sy > 15)
+               return -EINVAL;
+
+       dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy);
+       request.tcode           = TCODE_STREAM_DATA;
+       request.length          = p->length;
+       request.closure         = p->closure;
+       request.data            = p->data;
+       request.generation      = p->generation;
+
+       return init_request(client, &request, dest, p->speed);
+}
+
 static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
        ioctl_get_info,
        ioctl_send_request,
@@ -885,13 +1285,20 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
        ioctl_start_iso,
        ioctl_stop_iso,
        ioctl_get_cycle_timer,
+       ioctl_allocate_iso_resource,
+       ioctl_deallocate_iso_resource,
+       ioctl_allocate_iso_resource_once,
+       ioctl_deallocate_iso_resource_once,
+       ioctl_get_speed,
+       ioctl_send_broadcast_request,
+       ioctl_send_stream_packet,
 };
 
-static int
-dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
+static int dispatch_ioctl(struct client *client,
+                         unsigned int cmd, void __user *arg)
 {
        char buffer[256];
-       int retval;
+       int ret;
 
        if (_IOC_TYPE(cmd) != '#' ||
            _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers))
@@ -903,9 +1310,9 @@ dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
                        return -EFAULT;
        }
 
-       retval = ioctl_handlers[_IOC_NR(cmd)](client, buffer);
-       if (retval < 0)
-               return retval;
+       ret = ioctl_handlers[_IOC_NR(cmd)](client, buffer);
+       if (ret < 0)
+               return ret;
 
        if (_IOC_DIR(cmd) & _IOC_READ) {
                if (_IOC_SIZE(cmd) > sizeof(buffer) ||
@@ -913,12 +1320,11 @@ dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
                        return -EFAULT;
        }
 
-       return retval;
+       return ret;
 }
 
-static long
-fw_device_op_ioctl(struct file *file,
-                  unsigned int cmd, unsigned long arg)
+static long fw_device_op_ioctl(struct file *file,
+                              unsigned int cmd, unsigned long arg)
 {
        struct client *client = file->private_data;
 
@@ -929,9 +1335,8 @@ fw_device_op_ioctl(struct file *file,
 }
 
 #ifdef CONFIG_COMPAT
-static long
-fw_device_op_compat_ioctl(struct file *file,
-                         unsigned int cmd, unsigned long arg)
+static long fw_device_op_compat_ioctl(struct file *file,
+                                     unsigned int cmd, unsigned long arg)
 {
        struct client *client = file->private_data;
 
@@ -947,7 +1352,7 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
        struct client *client = file->private_data;
        enum dma_data_direction direction;
        unsigned long size;
-       int page_count, retval;
+       int page_count, ret;
 
        if (fw_device_is_shutdown(client->device))
                return -ENODEV;
@@ -973,48 +1378,57 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
        else
                direction = DMA_FROM_DEVICE;
 
-       retval = fw_iso_buffer_init(&client->buffer, client->device->card,
-                                   page_count, direction);
-       if (retval < 0)
-               return retval;
+       ret = fw_iso_buffer_init(&client->buffer, client->device->card,
+                                page_count, direction);
+       if (ret < 0)
+               return ret;
 
-       retval = fw_iso_buffer_map(&client->buffer, vma);
-       if (retval < 0)
+       ret = fw_iso_buffer_map(&client->buffer, vma);
+       if (ret < 0)
                fw_iso_buffer_destroy(&client->buffer, client->device->card);
 
-       return retval;
+       return ret;
+}
+
+static int shutdown_resource(int id, void *p, void *data)
+{
+       struct client_resource *r = p;
+       struct client *client = data;
+
+       r->release(client, r);
+       client_put(client);
+
+       return 0;
 }
 
 static int fw_device_op_release(struct inode *inode, struct file *file)
 {
        struct client *client = file->private_data;
        struct event *e, *next_e;
-       struct client_resource *r, *next_r;
-       unsigned long flags;
 
-       if (client->buffer.pages)
-               fw_iso_buffer_destroy(&client->buffer, client->device->card);
+       mutex_lock(&client->device->client_list_mutex);
+       list_del(&client->link);
+       mutex_unlock(&client->device->client_list_mutex);
 
        if (client->iso_context)
                fw_iso_context_destroy(client->iso_context);
 
-       list_for_each_entry_safe(r, next_r, &client->resource_list, link)
-               r->release(client, r);
+       if (client->buffer.pages)
+               fw_iso_buffer_destroy(&client->buffer, client->device->card);
 
-       /*
-        * FIXME: We should wait for the async tasklets to stop
-        * running before freeing the memory.
-        */
+       /* Freeze client->resource_idr and client->event_list */
+       spin_lock_irq(&client->lock);
+       client->in_shutdown = true;
+       spin_unlock_irq(&client->lock);
+
+       idr_for_each(&client->resource_idr, shutdown_resource, client);
+       idr_remove_all(&client->resource_idr);
+       idr_destroy(&client->resource_idr);
 
        list_for_each_entry_safe(e, next_e, &client->event_list, link)
                kfree(e);
 
-       spin_lock_irqsave(&client->device->card->lock, flags);
-       list_del(&client->link);
-       spin_unlock_irqrestore(&client->device->card->lock, flags);
-
-       fw_device_put(client->device);
-       kfree(client);
+       client_put(client);
 
        return 0;
 }
index bf53acb45652ad161319955204da767c0e7edfc3..a47e2129d83d3a5f99aa7165a6600f3bea9b5383 100644 (file)
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include <linux/module.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/kthread.h>
-#include <linux/device.h>
+#include <linux/ctype.h>
 #include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
 #include <linux/idr.h>
 #include <linux/jiffies.h>
-#include <linux/string.h>
+#include <linux/kobject.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
 #include <linux/rwsem.h>
 #include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+
 #include <asm/system.h>
-#include <linux/ctype.h>
-#include "fw-transaction.h"
-#include "fw-topology.h"
+
 #include "fw-device.h"
+#include "fw-topology.h"
+#include "fw-transaction.h"
 
 void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p)
 {
@@ -132,8 +136,7 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
                        vendor, model, specifier_id, version);
 }
 
-static int
-fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct fw_unit *unit = fw_unit(dev);
        char modalias[64];
@@ -152,27 +155,6 @@ struct bus_type fw_bus_type = {
 };
 EXPORT_SYMBOL(fw_bus_type);
 
-static void fw_device_release(struct device *dev)
-{
-       struct fw_device *device = fw_device(dev);
-       struct fw_card *card = device->card;
-       unsigned long flags;
-
-       /*
-        * Take the card lock so we don't set this to NULL while a
-        * FW_NODE_UPDATED callback is being handled or while the
-        * bus manager work looks at this node.
-        */
-       spin_lock_irqsave(&card->lock, flags);
-       device->node->data = NULL;
-       spin_unlock_irqrestore(&card->lock, flags);
-
-       fw_node_put(device->node);
-       kfree(device->config_rom);
-       kfree(device);
-       fw_card_put(card);
-}
-
 int fw_device_enable_phys_dma(struct fw_device *device)
 {
        int generation = device->generation;
@@ -191,8 +173,8 @@ struct config_rom_attribute {
        u32 key;
 };
 
-static ssize_t
-show_immediate(struct device *dev, struct device_attribute *dattr, char *buf)
+static ssize_t show_immediate(struct device *dev,
+                             struct device_attribute *dattr, char *buf)
 {
        struct config_rom_attribute *attr =
                container_of(dattr, struct config_rom_attribute, attr);
@@ -223,8 +205,8 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf)
 #define IMMEDIATE_ATTR(name, key)                              \
        { __ATTR(name, S_IRUGO, show_immediate, NULL), key }
 
-static ssize_t
-show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf)
+static ssize_t show_text_leaf(struct device *dev,
+                             struct device_attribute *dattr, char *buf)
 {
        struct config_rom_attribute *attr =
                container_of(dattr, struct config_rom_attribute, attr);
@@ -293,10 +275,9 @@ static struct config_rom_attribute config_rom_attributes[] = {
        TEXT_LEAF_ATTR(hardware_version_name, CSR_HARDWARE_VERSION),
 };
 
-static void
-init_fw_attribute_group(struct device *dev,
-                       struct device_attribute *attrs,
-                       struct fw_attribute_group *group)
+static void init_fw_attribute_group(struct device *dev,
+                                   struct device_attribute *attrs,
+                                   struct fw_attribute_group *group)
 {
        struct device_attribute *attr;
        int i, j;
@@ -319,9 +300,8 @@ init_fw_attribute_group(struct device *dev,
        dev->groups = group->groups;
 }
 
-static ssize_t
-modalias_show(struct device *dev,
-             struct device_attribute *attr, char *buf)
+static ssize_t modalias_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
 {
        struct fw_unit *unit = fw_unit(dev);
        int length;
@@ -332,9 +312,8 @@ modalias_show(struct device *dev,
        return length + 1;
 }
 
-static ssize_t
-rom_index_show(struct device *dev,
-              struct device_attribute *attr, char *buf)
+static ssize_t rom_index_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
 {
        struct fw_device *device = fw_device(dev->parent);
        struct fw_unit *unit = fw_unit(dev);
@@ -349,8 +328,8 @@ static struct device_attribute fw_unit_attributes[] = {
        __ATTR_NULL,
 };
 
-static ssize_t
-config_rom_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t config_rom_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
 {
        struct fw_device *device = fw_device(dev);
        size_t length;
@@ -363,8 +342,8 @@ config_rom_show(struct device *dev, struct device_attribute *attr, char *buf)
        return length;
 }
 
-static ssize_t
-guid_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t guid_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
 {
        struct fw_device *device = fw_device(dev);
        int ret;
@@ -383,8 +362,8 @@ static struct device_attribute fw_device_attributes[] = {
        __ATTR_NULL,
 };
 
-static int
-read_rom(struct fw_device *device, int generation, int index, u32 *data)
+static int read_rom(struct fw_device *device,
+                   int generation, int index, u32 *data)
 {
        int rcode;
 
@@ -539,7 +518,7 @@ static int read_bus_info_block(struct fw_device *device, int generation)
 
        kfree(old_rom);
        ret = 0;
-       device->cmc = rom[2] & 1 << 30;
+       device->cmc = rom[2] >> 30 & 1;
  out:
        kfree(rom);
 
@@ -679,11 +658,53 @@ static void fw_device_shutdown(struct work_struct *work)
        fw_device_put(device);
 }
 
+static void fw_device_release(struct device *dev)
+{
+       struct fw_device *device = fw_device(dev);
+       struct fw_card *card = device->card;
+       unsigned long flags;
+
+       /*
+        * Take the card lock so we don't set this to NULL while a
+        * FW_NODE_UPDATED callback is being handled or while the
+        * bus manager work looks at this node.
+        */
+       spin_lock_irqsave(&card->lock, flags);
+       device->node->data = NULL;
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       fw_node_put(device->node);
+       kfree(device->config_rom);
+       kfree(device);
+       fw_card_put(card);
+}
+
 static struct device_type fw_device_type = {
-       .release        = fw_device_release,
+       .release = fw_device_release,
 };
 
-static void fw_device_update(struct work_struct *work);
+static int update_unit(struct device *dev, void *data)
+{
+       struct fw_unit *unit = fw_unit(dev);
+       struct fw_driver *driver = (struct fw_driver *)dev->driver;
+
+       if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {
+               down(&dev->sem);
+               driver->update(unit);
+               up(&dev->sem);
+       }
+
+       return 0;
+}
+
+static void fw_device_update(struct work_struct *work)
+{
+       struct fw_device *device =
+               container_of(work, struct fw_device, work.work);
+
+       fw_device_cdev_update(device);
+       device_for_each_child(&device->device, NULL, update_unit);
+}
 
 /*
  * If a device was pending for deletion because its node went away but its
@@ -735,12 +756,50 @@ static int lookup_existing_device(struct device *dev, void *data)
        return match;
 }
 
+enum { BC_UNKNOWN = 0, BC_UNIMPLEMENTED, BC_IMPLEMENTED, };
+
+void fw_device_set_broadcast_channel(struct fw_device *device, int generation)
+{
+       struct fw_card *card = device->card;
+       __be32 data;
+       int rcode;
+
+       if (!card->broadcast_channel_allocated)
+               return;
+
+       if (device->bc_implemented == BC_UNKNOWN) {
+               rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST,
+                               device->node_id, generation, device->max_speed,
+                               CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL,
+                               &data, 4);
+               switch (rcode) {
+               case RCODE_COMPLETE:
+                       if (data & cpu_to_be32(1 << 31)) {
+                               device->bc_implemented = BC_IMPLEMENTED;
+                               break;
+                       }
+                       /* else fall through to case address error */
+               case RCODE_ADDRESS_ERROR:
+                       device->bc_implemented = BC_UNIMPLEMENTED;
+               }
+       }
+
+       if (device->bc_implemented == BC_IMPLEMENTED) {
+               data = cpu_to_be32(BROADCAST_CHANNEL_INITIAL |
+                                  BROADCAST_CHANNEL_VALID);
+               fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST,
+                               device->node_id, generation, device->max_speed,
+                               CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL,
+                               &data, 4);
+       }
+}
+
 static void fw_device_init(struct work_struct *work)
 {
        struct fw_device *device =
                container_of(work, struct fw_device, work.work);
        struct device *revived_dev;
-       int minor, err;
+       int minor, ret;
 
        /*
         * All failure paths here set node->data to NULL, so that we
@@ -776,12 +835,12 @@ static void fw_device_init(struct work_struct *work)
 
        fw_device_get(device);
        down_write(&fw_device_rwsem);
-       err = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
+       ret = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
              idr_get_new(&fw_device_idr, device, &minor) :
              -ENOMEM;
        up_write(&fw_device_rwsem);
 
-       if (err < 0)
+       if (ret < 0)
                goto error;
 
        device->device.bus = &fw_bus_type;
@@ -828,6 +887,8 @@ static void fw_device_init(struct work_struct *work)
                                  device->config_rom[3], device->config_rom[4],
                                  1 << device->max_speed);
                device->config_rom_retries = 0;
+
+               fw_device_set_broadcast_channel(device, device->generation);
        }
 
        /*
@@ -851,29 +912,6 @@ static void fw_device_init(struct work_struct *work)
        put_device(&device->device);    /* our reference */
 }
 
-static int update_unit(struct device *dev, void *data)
-{
-       struct fw_unit *unit = fw_unit(dev);
-       struct fw_driver *driver = (struct fw_driver *)dev->driver;
-
-       if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {
-               down(&dev->sem);
-               driver->update(unit);
-               up(&dev->sem);
-       }
-
-       return 0;
-}
-
-static void fw_device_update(struct work_struct *work)
-{
-       struct fw_device *device =
-               container_of(work, struct fw_device, work.work);
-
-       fw_device_cdev_update(device);
-       device_for_each_child(&device->device, NULL, update_unit);
-}
-
 enum {
        REREAD_BIB_ERROR,
        REREAD_BIB_GONE,
@@ -894,7 +932,7 @@ static int reread_bus_info_block(struct fw_device *device, int generation)
                if (i == 0 && q == 0)
                        return REREAD_BIB_GONE;
 
-               if (i > device->config_rom_length || q != device->config_rom[i])
+               if (q != device->config_rom[i])
                        return REREAD_BIB_CHANGED;
        }
 
@@ -1004,6 +1042,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                device->node = fw_node_get(node);
                device->node_id = node->node_id;
                device->generation = card->generation;
+               mutex_init(&device->client_list_mutex);
                INIT_LIST_HEAD(&device->client_list);
 
                /*
index 8ef6ec2ca21cbc43288affa50a9cea19e7fbd5ae..97588937c0185167446ee29dda3abb50087075e0 100644 (file)
 #ifndef __fw_device_h
 #define __fw_device_h
 
+#include <linux/device.h>
 #include <linux/fs.h>
-#include <linux/cdev.h>
 #include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
 #include <linux/rwsem.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
 #include <asm/atomic.h>
 
 enum fw_device_state {
@@ -38,6 +45,9 @@ struct fw_attribute_group {
        struct attribute *attrs[11];
 };
 
+struct fw_node;
+struct fw_card;
+
 /*
  * Note, fw_device.generation always has to be read before fw_device.node_id.
  * Use SMP memory barriers to ensure this.  Otherwise requests will be sent
@@ -61,13 +71,18 @@ struct fw_device {
        int node_id;
        int generation;
        unsigned max_speed;
-       bool cmc;
        struct fw_card *card;
        struct device device;
+
+       struct mutex client_list_mutex;
        struct list_head client_list;
+
        u32 *config_rom;
        size_t config_rom_length;
        int config_rom_retries;
+       unsigned cmc:1;
+       unsigned bc_implemented:2;
+
        struct delayed_work work;
        struct fw_attribute_group attribute_group;
 };
@@ -96,6 +111,7 @@ static inline void fw_device_put(struct fw_device *device)
 
 struct fw_device *fw_device_get_by_devt(dev_t devt);
 int fw_device_enable_phys_dma(struct fw_device *device);
+void fw_device_set_broadcast_channel(struct fw_device *device, int generation);
 
 void fw_device_cdev_update(struct fw_device *device);
 void fw_device_cdev_remove(struct fw_device *device);
@@ -176,8 +192,7 @@ struct fw_driver {
        const struct fw_device_id *id_table;
 };
 
-static inline struct fw_driver *
-fw_driver(struct device_driver *drv)
+static inline struct fw_driver *fw_driver(struct device_driver *drv)
 {
        return container_of(drv, struct fw_driver, driver);
 }
index e14c03dc006588d1b98d0b10ded8bd210d8fdb8d..2baf1007253e66a972b357d37b62b1e245d26bcd 100644 (file)
@@ -1,5 +1,7 @@
 /*
- * Isochronous IO functionality
+ * Isochronous I/O functionality:
+ *   - Isochronous DMA context management
+ *   - Isochronous bus resource management (channels, bandwidth), client side
  *
  * Copyright (C) 2006 Kristian Hoegsberg <krh@bitplanet.net>
  *
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/dma-mapping.h>
-#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/firewire-constants.h>
+#include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
 
-#include "fw-transaction.h"
 #include "fw-topology.h"
-#include "fw-device.h"
+#include "fw-transaction.h"
 
-int
-fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
-                  int page_count, enum dma_data_direction direction)
+/*
+ * Isochronous DMA context management
+ */
+
+int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
+                      int page_count, enum dma_data_direction direction)
 {
-       int i, j, retval = -ENOMEM;
+       int i, j;
        dma_addr_t address;
 
        buffer->page_count = page_count;
@@ -69,19 +75,21 @@ fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
        kfree(buffer->pages);
  out:
        buffer->pages = NULL;
-       return retval;
+
+       return -ENOMEM;
 }
 
 int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
 {
        unsigned long uaddr;
-       int i, retval;
+       int i, err;
 
        uaddr = vma->vm_start;
        for (i = 0; i < buffer->page_count; i++) {
-               retval = vm_insert_page(vma, uaddr, buffer->pages[i]);
-               if (retval)
-                       return retval;
+               err = vm_insert_page(vma, uaddr, buffer->pages[i]);
+               if (err)
+                       return err;
+
                uaddr += PAGE_SIZE;
        }
 
@@ -105,14 +113,14 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
        buffer->pages = NULL;
 }
 
-struct fw_iso_context *
-fw_iso_context_create(struct fw_card *card, int type,
-                     int channel, int speed, size_t header_size,
-                     fw_iso_callback_t callback, void *callback_data)
+struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
+               int type, int channel, int speed, size_t header_size,
+               fw_iso_callback_t callback, void *callback_data)
 {
        struct fw_iso_context *ctx;
 
-       ctx = card->driver->allocate_iso_context(card, type, header_size);
+       ctx = card->driver->allocate_iso_context(card,
+                                                type, channel, header_size);
        if (IS_ERR(ctx))
                return ctx;
 
@@ -134,25 +142,186 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx)
        card->driver->free_iso_context(ctx);
 }
 
-int
-fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags)
+int fw_iso_context_start(struct fw_iso_context *ctx,
+                        int cycle, int sync, int tags)
 {
        return ctx->card->driver->start_iso(ctx, cycle, sync, tags);
 }
 
-int
-fw_iso_context_queue(struct fw_iso_context *ctx,
-                    struct fw_iso_packet *packet,
-                    struct fw_iso_buffer *buffer,
-                    unsigned long payload)
+int fw_iso_context_queue(struct fw_iso_context *ctx,
+                        struct fw_iso_packet *packet,
+                        struct fw_iso_buffer *buffer,
+                        unsigned long payload)
 {
        struct fw_card *card = ctx->card;
 
        return card->driver->queue_iso(ctx, packet, buffer, payload);
 }
 
-int
-fw_iso_context_stop(struct fw_iso_context *ctx)
+int fw_iso_context_stop(struct fw_iso_context *ctx)
 {
        return ctx->card->driver->stop_iso(ctx);
 }
+
+/*
+ * Isochronous bus resource management (channels, bandwidth), client side
+ */
+
+static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
+                           int bandwidth, bool allocate)
+{
+       __be32 data[2];
+       int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0;
+
+       /*
+        * On a 1394a IRM with low contention, try < 1 is enough.
+        * On a 1394-1995 IRM, we need at least try < 2.
+        * Let's just do try < 5.
+        */
+       for (try = 0; try < 5; try++) {
+               new = allocate ? old - bandwidth : old + bandwidth;
+               if (new < 0 || new > BANDWIDTH_AVAILABLE_INITIAL)
+                       break;
+
+               data[0] = cpu_to_be32(old);
+               data[1] = cpu_to_be32(new);
+               switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
+                               irm_id, generation, SCODE_100,
+                               CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE,
+                               data, sizeof(data))) {
+               case RCODE_GENERATION:
+                       /* A generation change frees all bandwidth. */
+                       return allocate ? -EAGAIN : bandwidth;
+
+               case RCODE_COMPLETE:
+                       if (be32_to_cpup(data) == old)
+                               return bandwidth;
+
+                       old = be32_to_cpup(data);
+                       /* Fall through. */
+               }
+       }
+
+       return -EIO;
+}
+
+static int manage_channel(struct fw_card *card, int irm_id, int generation,
+                         u32 channels_mask, u64 offset, bool allocate)
+{
+       __be32 data[2], c, all, old;
+       int i, retry = 5;
+
+       old = all = allocate ? cpu_to_be32(~0) : 0;
+
+       for (i = 0; i < 32; i++) {
+               if (!(channels_mask & 1 << i))
+                       continue;
+
+               c = cpu_to_be32(1 << (31 - i));
+               if ((old & c) != (all & c))
+                       continue;
+
+               data[0] = old;
+               data[1] = old ^ c;
+               switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
+                                          irm_id, generation, SCODE_100,
+                                          offset, data, sizeof(data))) {
+               case RCODE_GENERATION:
+                       /* A generation change frees all channels. */
+                       return allocate ? -EAGAIN : i;
+
+               case RCODE_COMPLETE:
+                       if (data[0] == old)
+                               return i;
+
+                       old = data[0];
+
+                       /* Is the IRM 1394a-2000 compliant? */
+                       if ((data[0] & c) == (data[1] & c))
+                               continue;
+
+                       /* 1394-1995 IRM, fall through to retry. */
+               default:
+                       if (retry--)
+                               i--;
+               }
+       }
+
+       return -EIO;
+}
+
+static void deallocate_channel(struct fw_card *card, int irm_id,
+                              int generation, int channel)
+{
+       u32 mask;
+       u64 offset;
+
+       mask = channel < 32 ? 1 << channel : 1 << (channel - 32);
+       offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI :
+                               CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO;
+
+       manage_channel(card, irm_id, generation, mask, offset, false);
+}
+
+/**
+ * fw_iso_resource_manage - Allocate or deallocate a channel and/or bandwidth
+ *
+ * In parameters: card, generation, channels_mask, bandwidth, allocate
+ * Out parameters: channel, bandwidth
+ * This function blocks (sleeps) during communication with the IRM.
+ *
+ * Allocates or deallocates at most one channel out of channels_mask.
+ * channels_mask is a bitfield with MSB for channel 63 and LSB for channel 0.
+ * (Note, the IRM's CHANNELS_AVAILABLE is a big-endian bitfield with MSB for
+ * channel 0 and LSB for channel 63.)
+ * Allocates or deallocates as many bandwidth allocation units as specified.
+ *
+ * Returns channel < 0 if no channel was allocated or deallocated.
+ * Returns bandwidth = 0 if no bandwidth was allocated or deallocated.
+ *
+ * If generation is stale, deallocations succeed but allocations fail with
+ * channel = -EAGAIN.
+ *
+ * If channel allocation fails, no bandwidth will be allocated either.
+ * If bandwidth allocation fails, no channel will be allocated either.
+ * But deallocations of channel and bandwidth are tried independently
+ * of each other's success.
+ */
+void fw_iso_resource_manage(struct fw_card *card, int generation,
+                           u64 channels_mask, int *channel, int *bandwidth,
+                           bool allocate)
+{
+       u32 channels_hi = channels_mask;        /* channels 31...0 */
+       u32 channels_lo = channels_mask >> 32;  /* channels 63...32 */
+       int irm_id, ret, c = -EINVAL;
+
+       spin_lock_irq(&card->lock);
+       irm_id = card->irm_node->node_id;
+       spin_unlock_irq(&card->lock);
+
+       if (channels_hi)
+               c = manage_channel(card, irm_id, generation, channels_hi,
+                   CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI, allocate);
+       if (channels_lo && c < 0) {
+               c = manage_channel(card, irm_id, generation, channels_lo,
+                   CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO, allocate);
+               if (c >= 0)
+                       c += 32;
+       }
+       *channel = c;
+
+       if (allocate && channels_mask != 0 && c < 0)
+               *bandwidth = 0;
+
+       if (*bandwidth == 0)
+               return;
+
+       ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate);
+       if (ret < 0)
+               *bandwidth = 0;
+
+       if (allocate && ret < 0 && c >= 0) {
+               deallocate_channel(card, irm_id, generation, c);
+               *channel = ret;
+       }
+}
index 6d19828a93a5a458e8254a1d33b4bd3d5fd59f0a..1180d0be0bb4c0536cd7917cbd68910518f67450 100644 (file)
@@ -205,6 +205,7 @@ struct fw_ohci {
 
        u32 it_context_mask;
        struct iso_context *it_context_list;
+       u64 ir_context_channels;
        u32 ir_context_mask;
        struct iso_context *ir_context_list;
 };
@@ -441,9 +442,8 @@ static inline void flush_writes(const struct fw_ohci *ohci)
        reg_read(ohci, OHCI1394_Version);
 }
 
-static int
-ohci_update_phy_reg(struct fw_card *card, int addr,
-                   int clear_bits, int set_bits)
+static int ohci_update_phy_reg(struct fw_card *card, int addr,
+                              int clear_bits, int set_bits)
 {
        struct fw_ohci *ohci = fw_ohci(card);
        u32 val, old;
@@ -658,8 +658,8 @@ static void ar_context_tasklet(unsigned long data)
        }
 }
 
-static int
-ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, u32 regs)
+static int ar_context_init(struct ar_context *ctx,
+                          struct fw_ohci *ohci, u32 regs)
 {
        struct ar_buffer ab;
 
@@ -690,8 +690,7 @@ static void ar_context_run(struct ar_context *ctx)
        flush_writes(ctx->ohci);
 }
 
-static struct descriptor *
-find_branch_descriptor(struct descriptor *d, int z)
+static struct descriptor *find_branch_descriptor(struct descriptor *d, int z)
 {
        int b, key;
 
@@ -751,8 +750,7 @@ static void context_tasklet(unsigned long data)
  * Allocate a new buffer and add it to the list of free buffers for this
  * context.  Must be called with ohci->lock held.
  */
-static int
-context_add_buffer(struct context *ctx)
+static int context_add_buffer(struct context *ctx)
 {
        struct descriptor_buffer *desc;
        dma_addr_t uninitialized_var(bus_addr);
@@ -781,9 +779,8 @@ context_add_buffer(struct context *ctx)
        return 0;
 }
 
-static int
-context_init(struct context *ctx, struct fw_ohci *ohci,
-            u32 regs, descriptor_callback_t callback)
+static int context_init(struct context *ctx, struct fw_ohci *ohci,
+                       u32 regs, descriptor_callback_t callback)
 {
        ctx->ohci = ohci;
        ctx->regs = regs;
@@ -814,8 +811,7 @@ context_init(struct context *ctx, struct fw_ohci *ohci,
        return 0;
 }
 
-static void
-context_release(struct context *ctx)
+static void context_release(struct context *ctx)
 {
        struct fw_card *card = &ctx->ohci->card;
        struct descriptor_buffer *desc, *tmp;
@@ -827,8 +823,8 @@ context_release(struct context *ctx)
 }
 
 /* Must be called with ohci->lock held */
-static struct descriptor *
-context_get_descriptors(struct context *ctx, int z, dma_addr_t *d_bus)
+static struct descriptor *context_get_descriptors(struct context *ctx,
+                                                 int z, dma_addr_t *d_bus)
 {
        struct descriptor *d = NULL;
        struct descriptor_buffer *desc = ctx->buffer_tail;
@@ -912,8 +908,8 @@ struct driver_data {
  * Must always be called with the ochi->lock held to ensure proper
  * generation handling and locking around packet queue manipulation.
  */
-static int
-at_context_queue_packet(struct context *ctx, struct fw_packet *packet)
+static int at_context_queue_packet(struct context *ctx,
+                                  struct fw_packet *packet)
 {
        struct fw_ohci *ohci = ctx->ohci;
        dma_addr_t d_bus, uninitialized_var(payload_bus);
@@ -940,7 +936,9 @@ at_context_queue_packet(struct context *ctx, struct fw_packet *packet)
         */
 
        header = (__le32 *) &d[1];
-       if (packet->header_length > 8) {
+       switch (packet->header_length) {
+       case 16:
+       case 12:
                header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
                                        (packet->speed << 16));
                header[1] = cpu_to_le32((packet->header[1] & 0xffff) |
@@ -954,12 +952,27 @@ at_context_queue_packet(struct context *ctx, struct fw_packet *packet)
                        header[3] = (__force __le32) packet->header[3];
 
                d[0].req_count = cpu_to_le16(packet->header_length);
-       } else {
+               break;
+
+       case 8:
                header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) |
                                        (packet->speed << 16));
                header[1] = cpu_to_le32(packet->header[0]);
                header[2] = cpu_to_le32(packet->header[1]);
                d[0].req_count = cpu_to_le16(12);
+               break;
+
+       case 4:
+               header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
+                                       (packet->speed << 16));
+               header[1] = cpu_to_le32(packet->header[0] & 0xffff0000);
+               d[0].req_count = cpu_to_le16(8);
+               break;
+
+       default:
+               /* BUG(); */
+               packet->ack = RCODE_SEND_ERROR;
+               return -1;
        }
 
        driver_data = (struct driver_data *) &d[3];
@@ -1095,8 +1108,8 @@ static int handle_at_packet(struct context *context,
 #define HEADER_GET_DATA_LENGTH(q)      (((q) >> 16) & 0xffff)
 #define HEADER_GET_EXTENDED_TCODE(q)   (((q) >> 0) & 0xffff)
 
-static void
-handle_local_rom(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr)
+static void handle_local_rom(struct fw_ohci *ohci,
+                            struct fw_packet *packet, u32 csr)
 {
        struct fw_packet response;
        int tcode, length, i;
@@ -1122,8 +1135,8 @@ handle_local_rom(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr)
        fw_core_handle_response(&ohci->card, &response);
 }
 
-static void
-handle_local_lock(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr)
+static void handle_local_lock(struct fw_ohci *ohci,
+                             struct fw_packet *packet, u32 csr)
 {
        struct fw_packet response;
        int tcode, length, ext_tcode, sel;
@@ -1164,8 +1177,7 @@ handle_local_lock(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr)
        fw_core_handle_response(&ohci->card, &response);
 }
 
-static void
-handle_local_request(struct context *ctx, struct fw_packet *packet)
+static void handle_local_request(struct context *ctx, struct fw_packet *packet)
 {
        u64 offset;
        u32 csr;
@@ -1205,11 +1217,10 @@ handle_local_request(struct context *ctx, struct fw_packet *packet)
        }
 }
 
-static void
-at_context_transmit(struct context *ctx, struct fw_packet *packet)
+static void at_context_transmit(struct context *ctx, struct fw_packet *packet)
 {
        unsigned long flags;
-       int retval;
+       int ret;
 
        spin_lock_irqsave(&ctx->ohci->lock, flags);
 
@@ -1220,10 +1231,10 @@ at_context_transmit(struct context *ctx, struct fw_packet *packet)
                return;
        }
 
-       retval = at_context_queue_packet(ctx, packet);
+       ret = at_context_queue_packet(ctx, packet);
        spin_unlock_irqrestore(&ctx->ohci->lock, flags);
 
-       if (retval < 0)
+       if (ret < 0)
                packet->callback(packet, &ctx->ohci->card, packet->ack);
 
 }
@@ -1590,12 +1601,12 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
        return 0;
 }
 
-static int
-ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length)
+static int ohci_set_config_rom(struct fw_card *card,
+                              u32 *config_rom, size_t length)
 {
        struct fw_ohci *ohci;
        unsigned long flags;
-       int retval = -EBUSY;
+       int ret = -EBUSY;
        __be32 *next_config_rom;
        dma_addr_t uninitialized_var(next_config_rom_bus);
 
@@ -1649,7 +1660,7 @@ ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length)
 
                reg_write(ohci, OHCI1394_ConfigROMmap,
                          ohci->next_config_rom_bus);
-               retval = 0;
+               ret = 0;
        }
 
        spin_unlock_irqrestore(&ohci->lock, flags);
@@ -1661,13 +1672,13 @@ ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length)
         * controller could need to access it before the bus reset
         * takes effect.
         */
-       if (retval == 0)
+       if (ret == 0)
                fw_core_initiate_bus_reset(&ohci->card, 1);
        else
                dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
                                  next_config_rom, next_config_rom_bus);
 
-       return retval;
+       return ret;
 }
 
 static void ohci_send_request(struct fw_card *card, struct fw_packet *packet)
@@ -1689,7 +1700,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
        struct fw_ohci *ohci = fw_ohci(card);
        struct context *ctx = &ohci->at_request_ctx;
        struct driver_data *driver_data = packet->driver_data;
-       int retval = -ENOENT;
+       int ret = -ENOENT;
 
        tasklet_disable(&ctx->tasklet);
 
@@ -1704,23 +1715,22 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
        driver_data->packet = NULL;
        packet->ack = RCODE_CANCELLED;
        packet->callback(packet, &ohci->card, packet->ack);
-       retval = 0;
-
+       ret = 0;
  out:
        tasklet_enable(&ctx->tasklet);
 
-       return retval;
+       return ret;
 }
 
-static int
-ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation)
+static int ohci_enable_phys_dma(struct fw_card *card,
+                               int node_id, int generation)
 {
 #ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA
        return 0;
 #else
        struct fw_ohci *ohci = fw_ohci(card);
        unsigned long flags;
-       int n, retval = 0;
+       int n, ret = 0;
 
        /*
         * FIXME:  Make sure this bitmask is cleared when we clear the busReset
@@ -1730,7 +1740,7 @@ ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation)
        spin_lock_irqsave(&ohci->lock, flags);
 
        if (ohci->generation != generation) {
-               retval = -ESTALE;
+               ret = -ESTALE;
                goto out;
        }
 
@@ -1748,12 +1758,12 @@ ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation)
        flush_writes(ohci);
  out:
        spin_unlock_irqrestore(&ohci->lock, flags);
-       return retval;
+
+       return ret;
 #endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
 }
 
-static u64
-ohci_get_bus_time(struct fw_card *card)
+static u64 ohci_get_bus_time(struct fw_card *card)
 {
        struct fw_ohci *ohci = fw_ohci(card);
        u32 cycle_time;
@@ -1765,6 +1775,28 @@ ohci_get_bus_time(struct fw_card *card)
        return bus_time;
 }
 
+static void copy_iso_headers(struct iso_context *ctx, void *p)
+{
+       int i = ctx->header_length;
+
+       if (i + ctx->base.header_size > PAGE_SIZE)
+               return;
+
+       /*
+        * The iso header is byteswapped to little endian by
+        * the controller, but the remaining header quadlets
+        * are big endian.  We want to present all the headers
+        * as big endian, so we have to swap the first quadlet.
+        */
+       if (ctx->base.header_size > 0)
+               *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
+       if (ctx->base.header_size > 4)
+               *(u32 *) (ctx->header + i + 4) = __swab32(*(u32 *) p);
+       if (ctx->base.header_size > 8)
+               memcpy(ctx->header + i + 8, p + 8, ctx->base.header_size - 8);
+       ctx->header_length += ctx->base.header_size;
+}
+
 static int handle_ir_dualbuffer_packet(struct context *context,
                                       struct descriptor *d,
                                       struct descriptor *last)
@@ -1775,7 +1807,6 @@ static int handle_ir_dualbuffer_packet(struct context *context,
        __le32 *ir_header;
        size_t header_length;
        void *p, *end;
-       int i;
 
        if (db->first_res_count != 0 && db->second_res_count != 0) {
                if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) {
@@ -1788,25 +1819,14 @@ static int handle_ir_dualbuffer_packet(struct context *context,
        header_length = le16_to_cpu(db->first_req_count) -
                le16_to_cpu(db->first_res_count);
 
-       i = ctx->header_length;
        p = db + 1;
        end = p + header_length;
-       while (p < end && i + ctx->base.header_size <= PAGE_SIZE) {
-               /*
-                * The iso header is byteswapped to little endian by
-                * the controller, but the remaining header quadlets
-                * are big endian.  We want to present all the headers
-                * as big endian, so we have to swap the first
-                * quadlet.
-                */
-               *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
-               memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4);
-               i += ctx->base.header_size;
+       while (p < end) {
+               copy_iso_headers(ctx, p);
                ctx->excess_bytes +=
                        (le32_to_cpu(*(__le32 *)(p + 4)) >> 16) & 0xffff;
-               p += ctx->base.header_size + 4;
+               p += max(ctx->base.header_size, (size_t)8);
        }
-       ctx->header_length = i;
 
        ctx->excess_bytes -= le16_to_cpu(db->second_req_count) -
                le16_to_cpu(db->second_res_count);
@@ -1832,7 +1852,6 @@ static int handle_ir_packet_per_buffer(struct context *context,
        struct descriptor *pd;
        __le32 *ir_header;
        void *p;
-       int i;
 
        for (pd = d; pd <= last; pd++) {
                if (pd->transfer_status)
@@ -1842,21 +1861,8 @@ static int handle_ir_packet_per_buffer(struct context *context,
                /* Descriptor(s) not done yet, stop iteration */
                return 0;
 
-       i   = ctx->header_length;
-       p   = last + 1;
-
-       if (ctx->base.header_size > 0 &&
-                       i + ctx->base.header_size <= PAGE_SIZE) {
-               /*
-                * The iso header is byteswapped to little endian by
-                * the controller, but the remaining header quadlets
-                * are big endian.  We want to present all the headers
-                * as big endian, so we have to swap the first quadlet.
-                */
-               *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
-               memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4);
-               ctx->header_length += ctx->base.header_size;
-       }
+       p = last + 1;
+       copy_iso_headers(ctx, p);
 
        if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {
                ir_header = (__le32 *) p;
@@ -1888,21 +1894,24 @@ static int handle_it_packet(struct context *context,
        return 1;
 }
 
-static struct fw_iso_context *
-ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
+static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
+                               int type, int channel, size_t header_size)
 {
        struct fw_ohci *ohci = fw_ohci(card);
        struct iso_context *ctx, *list;
        descriptor_callback_t callback;
+       u64 *channels, dont_care = ~0ULL;
        u32 *mask, regs;
        unsigned long flags;
-       int index, retval = -ENOMEM;
+       int index, ret = -ENOMEM;
 
        if (type == FW_ISO_CONTEXT_TRANSMIT) {
+               channels = &dont_care;
                mask = &ohci->it_context_mask;
                list = ohci->it_context_list;
                callback = handle_it_packet;
        } else {
+               channels = &ohci->ir_context_channels;
                mask = &ohci->ir_context_mask;
                list = ohci->ir_context_list;
                if (ohci->use_dualbuffer)
@@ -1912,9 +1921,11 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
        }
 
        spin_lock_irqsave(&ohci->lock, flags);
-       index = ffs(*mask) - 1;
-       if (index >= 0)
+       index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1;
+       if (index >= 0) {
+               *channels &= ~(1ULL << channel);
                *mask &= ~(1 << index);
+       }
        spin_unlock_irqrestore(&ohci->lock, flags);
 
        if (index < 0)
@@ -1932,8 +1943,8 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
        if (ctx->header == NULL)
                goto out;
 
-       retval = context_init(&ctx->context, ohci, regs, callback);
-       if (retval < 0)
+       ret = context_init(&ctx->context, ohci, regs, callback);
+       if (ret < 0)
                goto out_with_header;
 
        return &ctx->base;
@@ -1945,7 +1956,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
        *mask |= 1 << index;
        spin_unlock_irqrestore(&ohci->lock, flags);
 
-       return ERR_PTR(retval);
+       return ERR_PTR(ret);
 }
 
 static int ohci_start_iso(struct fw_iso_context *base,
@@ -2024,16 +2035,16 @@ static void ohci_free_iso_context(struct fw_iso_context *base)
        } else {
                index = ctx - ohci->ir_context_list;
                ohci->ir_context_mask |= 1 << index;
+               ohci->ir_context_channels |= 1ULL << base->channel;
        }
 
        spin_unlock_irqrestore(&ohci->lock, flags);
 }
 
-static int
-ohci_queue_iso_transmit(struct fw_iso_context *base,
-                       struct fw_iso_packet *packet,
-                       struct fw_iso_buffer *buffer,
-                       unsigned long payload)
+static int ohci_queue_iso_transmit(struct fw_iso_context *base,
+                                  struct fw_iso_packet *packet,
+                                  struct fw_iso_buffer *buffer,
+                                  unsigned long payload)
 {
        struct iso_context *ctx = container_of(base, struct iso_context, base);
        struct descriptor *d, *last, *pd;
@@ -2128,11 +2139,10 @@ ohci_queue_iso_transmit(struct fw_iso_context *base,
        return 0;
 }
 
-static int
-ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
-                                 struct fw_iso_packet *packet,
-                                 struct fw_iso_buffer *buffer,
-                                 unsigned long payload)
+static int ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
+                                            struct fw_iso_packet *packet,
+                                            struct fw_iso_buffer *buffer,
+                                            unsigned long payload)
 {
        struct iso_context *ctx = container_of(base, struct iso_context, base);
        struct db_descriptor *db = NULL;
@@ -2151,11 +2161,11 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
        z = 2;
 
        /*
-        * The OHCI controller puts the status word in the header
-        * buffer too, so we need 4 extra bytes per packet.
+        * The OHCI controller puts the isochronous header and trailer in the
+        * buffer, so we need at least 8 bytes.
         */
        packet_count = p->header_length / ctx->base.header_size;
-       header_size = packet_count * (ctx->base.header_size + 4);
+       header_size = packet_count * max(ctx->base.header_size, (size_t)8);
 
        /* Get header size in number of descriptors. */
        header_z = DIV_ROUND_UP(header_size, sizeof(*d));
@@ -2173,7 +2183,8 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
                db = (struct db_descriptor *) d;
                db->control = cpu_to_le16(DESCRIPTOR_STATUS |
                                          DESCRIPTOR_BRANCH_ALWAYS);
-               db->first_size = cpu_to_le16(ctx->base.header_size + 4);
+               db->first_size =
+                   cpu_to_le16(max(ctx->base.header_size, (size_t)8));
                if (p->skip && rest == p->payload_length) {
                        db->control |= cpu_to_le16(DESCRIPTOR_WAIT);
                        db->first_req_count = db->first_size;
@@ -2208,11 +2219,10 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
        return 0;
 }
 
-static int
-ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
-                                        struct fw_iso_packet *packet,
-                                        struct fw_iso_buffer *buffer,
-                                        unsigned long payload)
+static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
+                                       struct fw_iso_packet *packet,
+                                       struct fw_iso_buffer *buffer,
+                                       unsigned long payload)
 {
        struct iso_context *ctx = container_of(base, struct iso_context, base);
        struct descriptor *d = NULL, *pd = NULL;
@@ -2223,11 +2233,11 @@ ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
        int page, offset, packet_count, header_size, payload_per_buffer;
 
        /*
-        * The OHCI controller puts the status word in the
-        * buffer too, so we need 4 extra bytes per packet.
+        * The OHCI controller puts the isochronous header and trailer in the
+        * buffer, so we need at least 8 bytes.
         */
        packet_count = p->header_length / ctx->base.header_size;
-       header_size  = ctx->base.header_size + 4;
+       header_size  = max(ctx->base.header_size, (size_t)8);
 
        /* Get header size in number of descriptors. */
        header_z = DIV_ROUND_UP(header_size, sizeof(*d));
@@ -2286,29 +2296,27 @@ ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
        return 0;
 }
 
-static int
-ohci_queue_iso(struct fw_iso_context *base,
-              struct fw_iso_packet *packet,
-              struct fw_iso_buffer *buffer,
-              unsigned long payload)
+static int ohci_queue_iso(struct fw_iso_context *base,
+                         struct fw_iso_packet *packet,
+                         struct fw_iso_buffer *buffer,
+                         unsigned long payload)
 {
        struct iso_context *ctx = container_of(base, struct iso_context, base);
        unsigned long flags;
-       int retval;
+       int ret;
 
        spin_lock_irqsave(&ctx->context.ohci->lock, flags);
        if (base->type == FW_ISO_CONTEXT_TRANSMIT)
-               retval = ohci_queue_iso_transmit(base, packet, buffer, payload);
+               ret = ohci_queue_iso_transmit(base, packet, buffer, payload);
        else if (ctx->context.ohci->use_dualbuffer)
-               retval = ohci_queue_iso_receive_dualbuffer(base, packet,
-                                                        buffer, payload);
+               ret = ohci_queue_iso_receive_dualbuffer(base, packet,
+                                                       buffer, payload);
        else
-               retval = ohci_queue_iso_receive_packet_per_buffer(base, packet,
-                                                               buffer,
-                                                               payload);
+               ret = ohci_queue_iso_receive_packet_per_buffer(base, packet,
+                                                       buffer, payload);
        spin_unlock_irqrestore(&ctx->context.ohci->lock, flags);
 
-       return retval;
+       return ret;
 }
 
 static const struct fw_card_driver ohci_driver = {
@@ -2357,8 +2365,8 @@ static void ohci_pmac_off(struct pci_dev *dev)
 #define ohci_pmac_off(dev)
 #endif /* CONFIG_PPC_PMAC */
 
-static int __devinit
-pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+static int __devinit pci_probe(struct pci_dev *dev,
+                              const struct pci_device_id *ent)
 {
        struct fw_ohci *ohci;
        u32 bus_options, max_receive, link_speed, version;
@@ -2440,6 +2448,7 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
        ohci->it_context_list = kzalloc(size, GFP_KERNEL);
 
        reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
+       ohci->ir_context_channels = ~0ULL;
        ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
        reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
        size = sizeof(struct iso_context) * hweight32(ohci->ir_context_mask);
@@ -2467,11 +2476,12 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
                reg_read(ohci, OHCI1394_GUIDLo);
 
        err = fw_card_add(&ohci->card, max_receive, link_speed, guid);
-       if (err < 0)
+       if (err)
                goto fail_self_id;
 
        fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
                  dev_name(&dev->dev), version >> 16, version & 0xff);
+
        return 0;
 
  fail_self_id:
index c71c4419d9e82bd0cdaa07b591f7b6c722b5d1de..2bcf51557c72ae8300ae844106ed0d052f9eb068 100644 (file)
@@ -392,20 +392,18 @@ static const struct {
        }
 };
 
-static void
-free_orb(struct kref *kref)
+static void free_orb(struct kref *kref)
 {
        struct sbp2_orb *orb = container_of(kref, struct sbp2_orb, kref);
 
        kfree(orb);
 }
 
-static void
-sbp2_status_write(struct fw_card *card, struct fw_request *request,
-                 int tcode, int destination, int source,
-                 int generation, int speed,
-                 unsigned long long offset,
-                 void *payload, size_t length, void *callback_data)
+static void sbp2_status_write(struct fw_card *card, struct fw_request *request,
+                             int tcode, int destination, int source,
+                             int generation, int speed,
+                             unsigned long long offset,
+                             void *payload, size_t length, void *callback_data)
 {
        struct sbp2_logical_unit *lu = callback_data;
        struct sbp2_orb *orb;
@@ -451,9 +449,8 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request,
        fw_send_response(card, request, RCODE_COMPLETE);
 }
 
-static void
-complete_transaction(struct fw_card *card, int rcode,
-                    void *payload, size_t length, void *data)
+static void complete_transaction(struct fw_card *card, int rcode,
+                                void *payload, size_t length, void *data)
 {
        struct sbp2_orb *orb = data;
        unsigned long flags;
@@ -482,9 +479,8 @@ complete_transaction(struct fw_card *card, int rcode,
        kref_put(&orb->kref, free_orb);
 }
 
-static void
-sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
-             int node_id, int generation, u64 offset)
+static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
+                         int node_id, int generation, u64 offset)
 {
        struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
        unsigned long flags;
@@ -531,8 +527,8 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
        return retval;
 }
 
-static void
-complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
+static void complete_management_orb(struct sbp2_orb *base_orb,
+                                   struct sbp2_status *status)
 {
        struct sbp2_management_orb *orb =
                container_of(base_orb, struct sbp2_management_orb, base);
@@ -542,10 +538,9 @@ complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
        complete(&orb->done);
 }
 
-static int
-sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
-                        int generation, int function, int lun_or_login_id,
-                        void *response)
+static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
+                                   int generation, int function,
+                                   int lun_or_login_id, void *response)
 {
        struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
        struct sbp2_management_orb *orb;
@@ -652,9 +647,8 @@ static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
                           &d, sizeof(d));
 }
 
-static void
-complete_agent_reset_write_no_wait(struct fw_card *card, int rcode,
-                                  void *payload, size_t length, void *data)
+static void complete_agent_reset_write_no_wait(struct fw_card *card,
+               int rcode, void *payload, size_t length, void *data)
 {
        kfree(data);
 }
@@ -1299,8 +1293,7 @@ static void sbp2_unmap_scatterlist(struct device *card_device,
                                 sizeof(orb->page_table), DMA_TO_DEVICE);
 }
 
-static unsigned int
-sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data)
+static unsigned int sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data)
 {
        int sam_status;
 
@@ -1337,8 +1330,8 @@ sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data)
        }
 }
 
-static void
-complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
+static void complete_command_orb(struct sbp2_orb *base_orb,
+                                struct sbp2_status *status)
 {
        struct sbp2_command_orb *orb =
                container_of(base_orb, struct sbp2_command_orb, base);
@@ -1384,9 +1377,8 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
        orb->done(orb->cmd);
 }
 
-static int
-sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device,
-                    struct sbp2_logical_unit *lu)
+static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
+               struct fw_device *device, struct sbp2_logical_unit *lu)
 {
        struct scatterlist *sg = scsi_sglist(orb->cmd);
        int i, n;
@@ -1584,9 +1576,8 @@ static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
  * This is the concatenation of target port identifier and logical unit
  * identifier as per SAM-2...SAM-4 annex A.
  */
-static ssize_t
-sbp2_sysfs_ieee1394_id_show(struct device *dev, struct device_attribute *attr,
-                           char *buf)
+static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
 {
        struct scsi_device *sdev = to_scsi_device(dev);
        struct sbp2_logical_unit *lu;
index 8dd6703b55cd00702f64f84272d3d523d7112ec6..d0deecc4de938440c99c1c6778ca0917e71491d0 100644 (file)
@@ -314,9 +314,8 @@ typedef void (*fw_node_callback_t)(struct fw_card * card,
                                   struct fw_node * node,
                                   struct fw_node * parent);
 
-static void
-for_each_fw_node(struct fw_card *card, struct fw_node *root,
-                fw_node_callback_t callback)
+static void for_each_fw_node(struct fw_card *card, struct fw_node *root,
+                            fw_node_callback_t callback)
 {
        struct list_head list;
        struct fw_node *node, *next, *child, *parent;
@@ -349,9 +348,8 @@ for_each_fw_node(struct fw_card *card, struct fw_node *root,
                fw_node_put(node);
 }
 
-static void
-report_lost_node(struct fw_card *card,
-                struct fw_node *node, struct fw_node *parent)
+static void report_lost_node(struct fw_card *card,
+                            struct fw_node *node, struct fw_node *parent)
 {
        fw_node_event(card, node, FW_NODE_DESTROYED);
        fw_node_put(node);
@@ -360,9 +358,8 @@ report_lost_node(struct fw_card *card,
        card->bm_retries = 0;
 }
 
-static void
-report_found_node(struct fw_card *card,
-                 struct fw_node *node, struct fw_node *parent)
+static void report_found_node(struct fw_card *card,
+                             struct fw_node *node, struct fw_node *parent)
 {
        int b_path = (node->phy_speed == SCODE_BETA);
 
@@ -415,8 +412,7 @@ static void move_tree(struct fw_node *node0, struct fw_node *node1, int port)
  * found, lost or updated.  Update the nodes in the card topology tree
  * as we go.
  */
-static void
-update_tree(struct fw_card *card, struct fw_node *root)
+static void update_tree(struct fw_card *card, struct fw_node *root)
 {
        struct list_head list0, list1;
        struct fw_node *node0, *node1, *next1;
@@ -497,8 +493,8 @@ update_tree(struct fw_card *card, struct fw_node *root)
        }
 }
 
-static void
-update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count)
+static void update_topology_map(struct fw_card *card,
+                               u32 *self_ids, int self_id_count)
 {
        int node_count;
 
@@ -510,10 +506,8 @@ update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count)
        fw_compute_block_crc(card->topology_map);
 }
 
-void
-fw_core_handle_bus_reset(struct fw_card *card,
-                        int node_id, int generation,
-                        int self_id_count, u32 * self_ids)
+void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
+                             int self_id_count, u32 *self_ids)
 {
        struct fw_node *local_node;
        unsigned long flags;
@@ -532,6 +526,7 @@ fw_core_handle_bus_reset(struct fw_card *card,
 
        spin_lock_irqsave(&card->lock, flags);
 
+       card->broadcast_channel_allocated = false;
        card->node_id = node_id;
        /*
         * Update node_id before generation to prevent anybody from using
index addb9f8ea776f1196dd7f65b6f75cd3695d13425..3c497bb4fae47e76a3d1ecbe3a05a396306dba89 100644 (file)
 #ifndef __fw_topology_h
 #define __fw_topology_h
 
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include <asm/atomic.h>
+
 enum {
        FW_NODE_CREATED,
        FW_NODE_UPDATED,
@@ -51,26 +56,22 @@ struct fw_node {
        struct fw_node *ports[0];
 };
 
-static inline struct fw_node *
-fw_node_get(struct fw_node *node)
+static inline struct fw_node *fw_node_get(struct fw_node *node)
 {
        atomic_inc(&node->ref_count);
 
        return node;
 }
 
-static inline void
-fw_node_put(struct fw_node *node)
+static inline void fw_node_put(struct fw_node *node)
 {
        if (atomic_dec_and_test(&node->ref_count))
                kfree(node);
 }
 
-void
-fw_destroy_nodes(struct fw_card *card);
-
-int
-fw_compute_block_crc(u32 *block);
+struct fw_card;
+void fw_destroy_nodes(struct fw_card *card);
 
+int fw_compute_block_crc(u32 *block);
 
 #endif /* __fw_topology_h */
index 699ac041f39ac576fa7a12ffd2fdf45ff7fe1a48..283dac6d327db100853c1768be00f37dbc346b10 100644 (file)
 #define PHY_CONFIG_ROOT_ID(node_id)    ((((node_id) & 0x3f) << 24) | (1 << 23))
 #define PHY_IDENTIFIER(id)             ((id) << 30)
 
-static int
-close_transaction(struct fw_transaction *transaction,
-                 struct fw_card *card, int rcode,
-                 u32 *payload, size_t length)
+static int close_transaction(struct fw_transaction *transaction,
+                            struct fw_card *card, int rcode)
 {
        struct fw_transaction *t;
        unsigned long flags;
@@ -83,7 +81,7 @@ close_transaction(struct fw_transaction *transaction,
        spin_unlock_irqrestore(&card->lock, flags);
 
        if (&t->link != &card->transaction_list) {
-               t->callback(card, rcode, payload, length, t->callback_data);
+               t->callback(card, rcode, NULL, 0, t->callback_data);
                return 0;
        }
 
@@ -94,9 +92,8 @@ close_transaction(struct fw_transaction *transaction,
  * Only valid for transactions that are potentially pending (ie have
  * been sent).
  */
-int
-fw_cancel_transaction(struct fw_card *card,
-                     struct fw_transaction *transaction)
+int fw_cancel_transaction(struct fw_card *card,
+                         struct fw_transaction *transaction)
 {
        /*
         * Cancel the packet transmission if it's still queued.  That
@@ -112,20 +109,19 @@ fw_cancel_transaction(struct fw_card *card,
         * if the transaction is still pending and remove it in that case.
         */
 
-       return close_transaction(transaction, card, RCODE_CANCELLED, NULL, 0);
+       return close_transaction(transaction, card, RCODE_CANCELLED);
 }
 EXPORT_SYMBOL(fw_cancel_transaction);
 
-static void
-transmit_complete_callback(struct fw_packet *packet,
-                          struct fw_card *card, int status)
+static void transmit_complete_callback(struct fw_packet *packet,
+                                      struct fw_card *card, int status)
 {
        struct fw_transaction *t =
            container_of(packet, struct fw_transaction, packet);
 
        switch (status) {
        case ACK_COMPLETE:
-               close_transaction(t, card, RCODE_COMPLETE, NULL, 0);
+               close_transaction(t, card, RCODE_COMPLETE);
                break;
        case ACK_PENDING:
                t->timestamp = packet->timestamp;
@@ -133,31 +129,42 @@ transmit_complete_callback(struct fw_packet *packet,
        case ACK_BUSY_X:
        case ACK_BUSY_A:
        case ACK_BUSY_B:
-               close_transaction(t, card, RCODE_BUSY, NULL, 0);
+               close_transaction(t, card, RCODE_BUSY);
                break;
        case ACK_DATA_ERROR:
-               close_transaction(t, card, RCODE_DATA_ERROR, NULL, 0);
+               close_transaction(t, card, RCODE_DATA_ERROR);
                break;
        case ACK_TYPE_ERROR:
-               close_transaction(t, card, RCODE_TYPE_ERROR, NULL, 0);
+               close_transaction(t, card, RCODE_TYPE_ERROR);
                break;
        default:
                /*
                 * In this case the ack is really a juju specific
                 * rcode, so just forward that to the callback.
                 */
-               close_transaction(t, card, status, NULL, 0);
+               close_transaction(t, card, status);
                break;
        }
 }
 
-static void
-fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
+static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
                int destination_id, int source_id, int generation, int speed,
                unsigned long long offset, void *payload, size_t length)
 {
        int ext_tcode;
 
+       if (tcode == TCODE_STREAM_DATA) {
+               packet->header[0] =
+                       HEADER_DATA_LENGTH(length) |
+                       destination_id |
+                       HEADER_TCODE(TCODE_STREAM_DATA);
+               packet->header_length = 4;
+               packet->payload = payload;
+               packet->payload_length = length;
+
+               goto common;
+       }
+
        if (tcode > 0x10) {
                ext_tcode = tcode & ~0x10;
                tcode = TCODE_LOCK_REQUEST;
@@ -204,7 +211,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
                packet->payload_length = 0;
                break;
        }
-
+ common:
        packet->speed = speed;
        packet->generation = generation;
        packet->ack = 0;
@@ -246,13 +253,14 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
  * @param callback function to be called when the transaction is completed
  * @param callback_data pointer to arbitrary data, which will be
  *   passed to the callback
+ *
+ * In case of asynchronous stream packets i.e. TCODE_STREAM_DATA, the caller
+ * needs to synthesize @destination_id with fw_stream_packet_destination_id().
  */
-void
-fw_send_request(struct fw_card *card, struct fw_transaction *t,
-               int tcode, int destination_id, int generation, int speed,
-               unsigned long long offset,
-               void *payload, size_t length,
-               fw_transaction_callback_t callback, void *callback_data)
+void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
+                    int destination_id, int generation, int speed,
+                    unsigned long long offset, void *payload, size_t length,
+                    fw_transaction_callback_t callback, void *callback_data)
 {
        unsigned long flags;
        int tlabel;
@@ -322,16 +330,16 @@ static void transaction_callback(struct fw_card *card, int rcode,
  * Returns the RCODE.
  */
 int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
-               int generation, int speed, unsigned long long offset,
-               void *data, size_t length)
+                      int generation, int speed, unsigned long long offset,
+                      void *payload, size_t length)
 {
        struct transaction_callback_data d;
        struct fw_transaction t;
 
        init_completion(&d.done);
-       d.payload = data;
+       d.payload = payload;
        fw_send_request(card, &t, tcode, destination_id, generation, speed,
-                       offset, data, length, transaction_callback, &d);
+                       offset, payload, length, transaction_callback, &d);
        wait_for_completion(&d.done);
 
        return d.rcode;
@@ -399,9 +407,8 @@ void fw_flush_transactions(struct fw_card *card)
        }
 }
 
-static struct fw_address_handler *
-lookup_overlapping_address_handler(struct list_head *list,
-                                  unsigned long long offset, size_t length)
+static struct fw_address_handler *lookup_overlapping_address_handler(
+       struct list_head *list, unsigned long long offset, size_t length)
 {
        struct fw_address_handler *handler;
 
@@ -414,9 +421,8 @@ lookup_overlapping_address_handler(struct list_head *list,
        return NULL;
 }
 
-static struct fw_address_handler *
-lookup_enclosing_address_handler(struct list_head *list,
-                                unsigned long long offset, size_t length)
+static struct fw_address_handler *lookup_enclosing_address_handler(
+       struct list_head *list, unsigned long long offset, size_t length)
 {
        struct fw_address_handler *handler;
 
@@ -449,36 +455,44 @@ const struct fw_address_region fw_unit_space_region =
 #endif  /*  0  */
 
 /**
- * Allocate a range of addresses in the node space of the OHCI
- * controller.  When a request is received that falls within the
- * specified address range, the specified callback is invoked.  The
- * parameters passed to the callback give the details of the
- * particular request.
+ * fw_core_add_address_handler - register for incoming requests
+ * @handler: callback
+ * @region: region in the IEEE 1212 node space address range
+ *
+ * region->start, ->end, and handler->length have to be quadlet-aligned.
+ *
+ * When a request is received that falls within the specified address range,
+ * the specified callback is invoked.  The parameters passed to the callback
+ * give the details of the particular request.
  *
  * Return value:  0 on success, non-zero otherwise.
  * The start offset of the handler's address region is determined by
  * fw_core_add_address_handler() and is returned in handler->offset.
- * The offset is quadlet-aligned.
  */
-int
-fw_core_add_address_handler(struct fw_address_handler *handler,
-                           const struct fw_address_region *region)
+int fw_core_add_address_handler(struct fw_address_handler *handler,
+                               const struct fw_address_region *region)
 {
        struct fw_address_handler *other;
        unsigned long flags;
        int ret = -EBUSY;
 
+       if (region->start & 0xffff000000000003ULL ||
+           region->end   & 0xffff000000000003ULL ||
+           region->start >= region->end ||
+           handler->length & 3 ||
+           handler->length == 0)
+               return -EINVAL;
+
        spin_lock_irqsave(&address_handler_lock, flags);
 
-       handler->offset = roundup(region->start, 4);
+       handler->offset = region->start;
        while (handler->offset + handler->length <= region->end) {
                other =
                    lookup_overlapping_address_handler(&address_handler_list,
                                                       handler->offset,
                                                       handler->length);
                if (other != NULL) {
-                       handler->offset =
-                           roundup(other->offset + other->length, 4);
+                       handler->offset += other->length;
                } else {
                        list_add_tail(&handler->link, &address_handler_list);
                        ret = 0;
@@ -493,12 +507,7 @@ fw_core_add_address_handler(struct fw_address_handler *handler,
 EXPORT_SYMBOL(fw_core_add_address_handler);
 
 /**
- * Deallocate a range of addresses allocated with fw_allocate.  This
- * will call the associated callback one last time with a the special
- * tcode TCODE_DEALLOCATE, to let the client destroy the registered
- * callback data.  For convenience, the callback parameters offset and
- * length are set to the start and the length respectively for the
- * deallocated region, payload is set to NULL.
+ * fw_core_remove_address_handler - unregister an address handler
  */
 void fw_core_remove_address_handler(struct fw_address_handler *handler)
 {
@@ -518,9 +527,8 @@ struct fw_request {
        u32 data[0];
 };
 
-static void
-free_response_callback(struct fw_packet *packet,
-                      struct fw_card *card, int status)
+static void free_response_callback(struct fw_packet *packet,
+                                  struct fw_card *card, int status)
 {
        struct fw_request *request;
 
@@ -528,9 +536,8 @@ free_response_callback(struct fw_packet *packet,
        kfree(request);
 }
 
-void
-fw_fill_response(struct fw_packet *response, u32 *request_header,
-                int rcode, void *payload, size_t length)
+void fw_fill_response(struct fw_packet *response, u32 *request_header,
+                     int rcode, void *payload, size_t length)
 {
        int tcode, tlabel, extended_tcode, source, destination;
 
@@ -588,8 +595,7 @@ fw_fill_response(struct fw_packet *response, u32 *request_header,
 }
 EXPORT_SYMBOL(fw_fill_response);
 
-static struct fw_request *
-allocate_request(struct fw_packet *p)
+static struct fw_request *allocate_request(struct fw_packet *p)
 {
        struct fw_request *request;
        u32 *data, length;
@@ -649,8 +655,8 @@ allocate_request(struct fw_packet *p)
        return request;
 }
 
-void
-fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
+void fw_send_response(struct fw_card *card,
+                     struct fw_request *request, int rcode)
 {
        /* unified transaction or broadcast transaction: don't respond */
        if (request->ack != ACK_PENDING ||
@@ -670,8 +676,7 @@ fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
 }
 EXPORT_SYMBOL(fw_send_response);
 
-void
-fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
+void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
 {
        struct fw_address_handler *handler;
        struct fw_request *request;
@@ -719,8 +724,7 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
 }
 EXPORT_SYMBOL(fw_core_handle_request);
 
-void
-fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
+void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
 {
        struct fw_transaction *t;
        unsigned long flags;
@@ -793,12 +797,10 @@ static const struct fw_address_region topology_map_region =
        { .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP,
          .end   = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, };
 
-static void
-handle_topology_map(struct fw_card *card, struct fw_request *request,
-                   int tcode, int destination, int source,
-                   int generation, int speed,
-                   unsigned long long offset,
-                   void *payload, size_t length, void *callback_data)
+static void handle_topology_map(struct fw_card *card, struct fw_request *request,
+               int tcode, int destination, int source, int generation,
+               int speed, unsigned long long offset,
+               void *payload, size_t length, void *callback_data)
 {
        int i, start, end;
        __be32 *map;
@@ -832,12 +834,10 @@ static const struct fw_address_region registers_region =
        { .start = CSR_REGISTER_BASE,
          .end   = CSR_REGISTER_BASE | CSR_CONFIG_ROM, };
 
-static void
-handle_registers(struct fw_card *card, struct fw_request *request,
-                int tcode, int destination, int source,
-                int generation, int speed,
-                unsigned long long offset,
-                void *payload, size_t length, void *callback_data)
+static void handle_registers(struct fw_card *card, struct fw_request *request,
+               int tcode, int destination, int source, int generation,
+               int speed, unsigned long long offset,
+               void *payload, size_t length, void *callback_data)
 {
        int reg = offset & ~CSR_REGISTER_BASE;
        unsigned long long bus_time;
@@ -939,11 +939,11 @@ static struct fw_descriptor model_id_descriptor = {
 
 static int __init fw_core_init(void)
 {
-       int retval;
+       int ret;
 
-       retval = bus_register(&fw_bus_type);
-       if (retval < 0)
-               return retval;
+       ret = bus_register(&fw_bus_type);
+       if (ret < 0)
+               return ret;
 
        fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
        if (fw_cdev_major < 0) {
@@ -951,19 +951,10 @@ static int __init fw_core_init(void)
                return fw_cdev_major;
        }
 
-       retval = fw_core_add_address_handler(&topology_map,
-                                            &topology_map_region);
-       BUG_ON(retval < 0);
-
-       retval = fw_core_add_address_handler(&registers,
-                                            &registers_region);
-       BUG_ON(retval < 0);
-
-       /* Add the vendor textual descriptor. */
-       retval = fw_core_add_descriptor(&vendor_id_descriptor);
-       BUG_ON(retval < 0);
-       retval = fw_core_add_descriptor(&model_id_descriptor);
-       BUG_ON(retval < 0);
+       fw_core_add_address_handler(&topology_map, &topology_map_region);
+       fw_core_add_address_handler(&registers, &registers_region);
+       fw_core_add_descriptor(&vendor_id_descriptor);
+       fw_core_add_descriptor(&model_id_descriptor);
 
        return 0;
 }
index 1d78e9cc5940a5a2c51be2c8724157bd25b5369f..dfa799068f892c5db110c2d1e69c4b6dab4cc320 100644 (file)
 #define CSR_SPEED_MAP                  0x2000
 #define CSR_SPEED_MAP_END              0x3000
 
+#define BANDWIDTH_AVAILABLE_INITIAL    4915
 #define BROADCAST_CHANNEL_INITIAL      (1 << 31 | 31)
 #define BROADCAST_CHANNEL_VALID                (1 << 30)
 
 #define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
 #define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
 
-static inline void
-fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
+static inline void fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
 {
        u32    *dst = _dst;
        __be32 *src = _src;
@@ -99,8 +99,7 @@ fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
                dst[i] = be32_to_cpu(src[i]);
 }
 
-static inline void
-fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
+static inline void fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
 {
        fw_memcpy_from_be32(_dst, _src, size);
 }
@@ -125,8 +124,7 @@ typedef void (*fw_packet_callback_t)(struct fw_packet *packet,
                                     struct fw_card *card, int status);
 
 typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
-                                         void *data,
-                                         size_t length,
+                                         void *data, size_t length,
                                          void *callback_data);
 
 /*
@@ -141,12 +139,6 @@ typedef void (*fw_address_callback_t)(struct fw_card *card,
                                      void *data, size_t length,
                                      void *callback_data);
 
-typedef void (*fw_bus_reset_callback_t)(struct fw_card *handle,
-                                       int node_id, int generation,
-                                       u32 *self_ids,
-                                       int self_id_count,
-                                       void *callback_data);
-
 struct fw_packet {
        int speed;
        int generation;
@@ -187,12 +179,6 @@ struct fw_transaction {
        void *callback_data;
 };
 
-static inline struct fw_packet *
-fw_packet(struct list_head *l)
-{
-       return list_entry(l, struct fw_packet, link);
-}
-
 struct fw_address_handler {
        u64 offset;
        size_t length;
@@ -201,7 +187,6 @@ struct fw_address_handler {
        struct list_head link;
 };
 
-
 struct fw_address_region {
        u64 start;
        u64 end;
@@ -255,6 +240,7 @@ struct fw_card {
        int bm_retries;
        int bm_generation;
 
+       bool broadcast_channel_allocated;
        u32 broadcast_channel;
        u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
 };
@@ -315,10 +301,8 @@ struct fw_iso_packet {
 struct fw_iso_context;
 
 typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
-                                 u32 cycle,
-                                 size_t header_length,
-                                 void *header,
-                                 void *data);
+                                 u32 cycle, size_t header_length,
+                                 void *header, void *data);
 
 /*
  * An iso buffer is just a set of pages mapped for DMA in the
@@ -344,36 +328,25 @@ struct fw_iso_context {
        void *callback_data;
 };
 
-int
-fw_iso_buffer_init(struct fw_iso_buffer *buffer,
-                  struct fw_card *card,
-                  int page_count,
-                  enum dma_data_direction direction);
-int
-fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
-void
-fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
-
-struct fw_iso_context *
-fw_iso_context_create(struct fw_card *card, int type,
-                     int channel, int speed, size_t header_size,
-                     fw_iso_callback_t callback, void *callback_data);
-
-void
-fw_iso_context_destroy(struct fw_iso_context *ctx);
-
-int
-fw_iso_context_queue(struct fw_iso_context *ctx,
-                    struct fw_iso_packet *packet,
-                    struct fw_iso_buffer *buffer,
-                    unsigned long payload);
-
-int
-fw_iso_context_start(struct fw_iso_context *ctx,
-                    int cycle, int sync, int tags);
-
-int
-fw_iso_context_stop(struct fw_iso_context *ctx);
+int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
+                      int page_count, enum dma_data_direction direction);
+int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
+void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
+
+struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
+               int type, int channel, int speed, size_t header_size,
+               fw_iso_callback_t callback, void *callback_data);
+int fw_iso_context_queue(struct fw_iso_context *ctx,
+                        struct fw_iso_packet *packet,
+                        struct fw_iso_buffer *buffer,
+                        unsigned long payload);
+int fw_iso_context_start(struct fw_iso_context *ctx,
+                        int cycle, int sync, int tags);
+int fw_iso_context_stop(struct fw_iso_context *ctx);
+void fw_iso_context_destroy(struct fw_iso_context *ctx);
+
+void fw_iso_resource_manage(struct fw_card *card, int generation,
+               u64 channels_mask, int *channel, int *bandwidth, bool allocate);
 
 struct fw_card_driver {
        /*
@@ -415,7 +388,7 @@ struct fw_card_driver {
 
        struct fw_iso_context *
        (*allocate_iso_context)(struct fw_card *card,
-                               int type, size_t header_size);
+                               int type, int channel, size_t header_size);
        void (*free_iso_context)(struct fw_iso_context *ctx);
 
        int (*start_iso)(struct fw_iso_context *ctx,
@@ -429,54 +402,45 @@ struct fw_card_driver {
        int (*stop_iso)(struct fw_iso_context *ctx);
 };
 
-int
-fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
+int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
 
-void
-fw_send_request(struct fw_card *card, struct fw_transaction *t,
+void fw_send_request(struct fw_card *card, struct fw_transaction *t,
                int tcode, int destination_id, int generation, int speed,
-               unsigned long long offset, void *data, size_t length,
+               unsigned long long offset, void *payload, size_t length,
                fw_transaction_callback_t callback, void *callback_data);
-
-int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
-                      int generation, int speed, unsigned long long offset,
-                      void *data, size_t length);
-
 int fw_cancel_transaction(struct fw_card *card,
                          struct fw_transaction *transaction);
-
 void fw_flush_transactions(struct fw_card *card);
-
+int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
+                      int generation, int speed, unsigned long long offset,
+                      void *payload, size_t length);
 void fw_send_phy_config(struct fw_card *card,
                        int node_id, int generation, int gap_count);
 
+static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
+{
+       return tag << 14 | channel << 8 | sy;
+}
+
 /*
  * Called by the topology code to inform the device code of node
  * activity; found, lost, or updated nodes.
  */