diff options
194 files changed, 10146 insertions, 1960 deletions
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 9b10af65faaa..f74dfc419b56 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -71,12 +71,6 @@ INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_ .section .text.head,"ax",@progbits ENTRY(startup_32) -#ifdef CONFIG_PARAVIRT - movl %cs, %eax - testl $0x3, %eax - jnz startup_paravirt -#endif - /* * Set segments to known values. */ @@ -501,38 +495,6 @@ ignore_int: iret .section .text -#ifdef CONFIG_PARAVIRT -startup_paravirt: - cld - movl $(init_thread_union+THREAD_SIZE),%esp - - /* We take pains to preserve all the regs. */ - pushl %edx - pushl %ecx - pushl %eax - - pushl $__start_paravirtprobe -1: - movl 0(%esp), %eax - cmpl $__stop_paravirtprobe, %eax - je unhandled_paravirt - pushl (%eax) - movl 8(%esp), %eax - call *(%esp) - popl %eax - - movl 4(%esp), %eax - movl 8(%esp), %ecx - movl 12(%esp), %edx - - addl $4, (%esp) - jmp 1b - -unhandled_paravirt: - /* Nothing wanted us: we're screwed. */ - ud2 -#endif - /* * Real beginning of normal "text" segment */ diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c index 5c10f376bce1..faab09abca5e 100644 --- a/arch/i386/kernel/paravirt.c +++ b/arch/i386/kernel/paravirt.c @@ -19,7 +19,6 @@ #include <linux/module.h> #include <linux/efi.h> #include <linux/bcd.h> -#include <linux/start_kernel.h> #include <linux/highmem.h> #include <asm/bug.h> diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S index 23e8614edeee..80bec6640230 100644 --- a/arch/i386/kernel/vmlinux.lds.S +++ b/arch/i386/kernel/vmlinux.lds.S @@ -78,12 +78,6 @@ SECTIONS CONSTRUCTORS } :data - .paravirtprobe : AT(ADDR(.paravirtprobe) - LOAD_OFFSET) { - __start_paravirtprobe = .; - *(.paravirtprobe) - __stop_paravirtprobe = .; - } - . = ALIGN(4096); .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { __nosave_begin = .; diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 1a84719be264..098c62c29f9c 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -4,27 +4,23 @@ # config MMU - bool - default y + def_bool y config ZONE_DMA def_bool y depends on 64BIT config LOCKDEP_SUPPORT - bool - default y + def_bool y config STACKTRACE_SUPPORT - bool - default y + def_bool y config RWSEM_GENERIC_SPINLOCK bool config RWSEM_XCHGADD_ALGORITHM - bool - default y + def_bool y config ARCH_HAS_ILOG2_U32 bool @@ -35,8 +31,7 @@ config ARCH_HAS_ILOG2_U64 default n config GENERIC_HWEIGHT - bool - default y + def_bool y config GENERIC_TIME def_bool y @@ -55,8 +50,7 @@ config NO_DMA mainmenu "Linux Kernel Configuration" config S390 - bool - default y + def_bool y source "init/Kconfig" @@ -280,6 +274,10 @@ config WARN_STACK_SIZE config ARCH_POPULATES_NODE_MAP def_bool y +comment "Kernel preemption" + +source "kernel/Kconfig.preempt" + source "mm/Kconfig" config HOLES_IN_ZONE @@ -320,17 +318,6 @@ config QDIO_DEBUG comment "Misc" -config PREEMPT - bool "Preemptible Kernel" - help - This option reduces the latency of the kernel when reacting to - real-time or interactive events by allowing a low priority process to - be preempted even if it is in kernel mode executing a system call. - This allows applications to run more reliably even when the system is - under load. - - Say N if you are unsure. - config IPL bool "Builtin IPL record support" help @@ -488,6 +475,8 @@ config APPLDATA_NET_SUM This can also be compiled as a module, which will be called appldata_net_sum.o. +source kernel/Kconfig.hz + config NO_IDLE_HZ bool "No HZ timer ticks in idle" help @@ -535,18 +524,12 @@ endmenu source "net/Kconfig" config PCMCIA - bool - default n - -source "drivers/base/Kconfig" + def_bool n -source "drivers/connector/Kconfig" - -source "drivers/scsi/Kconfig" - -source "drivers/s390/Kconfig" +config CCW + def_bool y -source "drivers/net/Kconfig" +source "drivers/Kconfig" source "fs/Kconfig" diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 0e4da8a7d826..485b60c1983c 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-rc1 -# Wed Feb 21 10:44:30 2007 +# Linux kernel version: 2.6.21 +# Thu May 10 15:18:19 2007 # CONFIG_MMU=y CONFIG_ZONE_DMA=y @@ -14,6 +14,7 @@ CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_TIME=y CONFIG_GENERIC_BUG=y CONFIG_NO_IOMEM=y +CONFIG_NO_DMA=y CONFIG_S390=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -41,9 +42,11 @@ CONFIG_AUDIT=y # CONFIG_AUDITSYSCALL is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 # CONFIG_CPUSETS is not set CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y @@ -60,12 +63,14 @@ CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_SHMEM=y -CONFIG_SLAB=y CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 -# CONFIG_SLOB is not set # # Loadable module support @@ -128,6 +133,14 @@ CONFIG_CHECK_STACK=y CONFIG_STACK_GUARD=256 # CONFIG_WARN_STACK is not set CONFIG_ARCH_POPULATES_NODE_MAP=y + +# +# Kernel preemption +# +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_BKL=y CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -150,7 +163,6 @@ CONFIG_QDIO=y # # Misc # -CONFIG_PREEMPT=y CONFIG_IPL=y # CONFIG_IPL_TAPE is not set CONFIG_IPL_VM=y @@ -163,6 +175,11 @@ CONFIG_PFAULT=y CONFIG_VIRT_TIMER=y CONFIG_VIRT_CPU_ACCOUNTING=y # CONFIG_APPLDATA_BASE is not set +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 CONFIG_NO_IDLE_HZ=y CONFIG_NO_IDLE_HZ_INIT=y CONFIG_S390_HYPFS_FS=y @@ -177,7 +194,6 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -216,6 +232,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set @@ -240,7 +257,12 @@ CONFIG_IPV6_SIT=y # # SCTP Configuration (EXPERIMENTAL) # -# CONFIG_IP_SCTP is not set +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y # # TIPC Configuration (EXPERIMENTAL) @@ -263,9 +285,6 @@ CONFIG_IPV6_SIT=y # CONFIG_NET_SCHED=y CONFIG_NET_SCH_FIFO=y -CONFIG_NET_SCH_CLK_JIFFIES=y -# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set -# CONFIG_NET_SCH_CLK_CPU is not set # # Queueing/Scheduling @@ -308,11 +327,14 @@ CONFIG_NET_ESTIMATOR=y # # CONFIG_NET_PKTGEN is not set # CONFIG_NET_TCPPROBE is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -# CONFIG_IEEE80211 is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_RFKILL is not set # CONFIG_PCMCIA is not set +CONFIG_CCW=y + +# +# Device Drivers +# # # Generic Driver Options @@ -330,6 +352,37 @@ CONFIG_SYS_HYPERVISOR=y # CONFIG_CONNECTOR is not set # +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# S/390 block device drivers +# +CONFIG_BLK_DEV_XPRAM=m +# CONFIG_DCSSBLK is not set +CONFIG_DASD=y +CONFIG_DASD_PROFILE=y +CONFIG_DASD_ECKD=y +CONFIG_DASD_FBA=y +CONFIG_DASD_DIAG=y +CONFIG_DASD_EER=y + +# +# Misc devices +# +# CONFIG_BLINK is not set + +# # SCSI device support # # CONFIG_RAID_ATTRS is not set @@ -356,6 +409,7 @@ CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_WAIT_SCAN=m # # SCSI Transports @@ -372,34 +426,6 @@ CONFIG_SCSI_FC_ATTRS=y # CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_DEBUG is not set CONFIG_ZFCP=y -CONFIG_CCW=y - -# -# Block devices -# -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=m -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_CDROM_PKTCDVD is not set - -# -# S/390 block device drivers -# -CONFIG_BLK_DEV_XPRAM=m -# CONFIG_DCSSBLK is not set -CONFIG_DASD=y -CONFIG_DASD_PROFILE=y -CONFIG_DASD_ECKD=y -CONFIG_DASD_FBA=y -CONFIG_DASD_DIAG=y -CONFIG_DASD_EER=y -# CONFIG_ATA_OVER_ETH is not set # # Multi-device support (RAID and LVM) @@ -421,56 +447,7 @@ CONFIG_DM_MIRROR=y CONFIG_DM_ZERO=y CONFIG_DM_MULTIPATH=y # CONFIG_DM_MULTIPATH_EMC is not set - -# -# Character device drivers -# -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=2048 -# CONFIG_HANGCHECK_TIMER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set - -# -# S/390 character device drivers -# -CONFIG_TN3270=y -CONFIG_TN3270_TTY=y -CONFIG_TN3270_FS=m -CONFIG_TN3270_CONSOLE=y -CONFIG_TN3215=y -CONFIG_TN3215_CONSOLE=y -CONFIG_CCW_CONSOLE=y -CONFIG_SCLP_TTY=y -CONFIG_SCLP_CONSOLE=y -CONFIG_SCLP_VT220_TTY=y -CONFIG_SCLP_VT220_CONSOLE=y -CONFIG_SCLP_CPI=m -CONFIG_S390_TAPE=m - -# -# S/390 tape interface support -# -CONFIG_S390_TAPE_BLOCK=y - -# -# S/390 tape hardware support -# -CONFIG_S390_TAPE_34XX=m -# CONFIG_S390_TAPE_3590 is not set -# CONFIG_VMLOGRDR is not set -# CONFIG_VMCP is not set -# CONFIG_MONREADER is not set -CONFIG_MONWRITER=m - -# -# Cryptographic devices -# -CONFIG_ZCRYPT=m -# CONFIG_ZCRYPT_MONOLITHIC is not set +# CONFIG_DM_DELAY is not set # # Network device support @@ -482,10 +459,6 @@ CONFIG_EQUALIZER=m CONFIG_TUN=m # -# PHY device support -# - -# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -498,6 +471,7 @@ CONFIG_NET_ETHERNET=y # # Ethernet (10000 Mbit) # +CONFIG_MLX4_DEBUG=y # # Token Ring devices @@ -505,11 +479,6 @@ CONFIG_NET_ETHERNET=y # CONFIG_TR is not set # -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# # Wan interfaces # # CONFIG_WAN is not set @@ -537,6 +506,56 @@ CONFIG_CCWGROUP=y # CONFIG_NET_POLL_CONTROLLER is not set # +# Character devices +# +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=m +# CONFIG_R3964 is not set +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_HANGCHECK_TIMER is not set + +# +# S/390 character device drivers +# +CONFIG_TN3270=y +CONFIG_TN3270_TTY=y +CONFIG_TN3270_FS=m +CONFIG_TN3270_CONSOLE=y +CONFIG_TN3215=y +CONFIG_TN3215_CONSOLE=y +CONFIG_CCW_CONSOLE=y +CONFIG_SCLP=y +CONFIG_SCLP_TTY=y +CONFIG_SCLP_CONSOLE=y +CONFIG_SCLP_VT220_TTY=y +CONFIG_SCLP_VT220_CONSOLE=y +CONFIG_SCLP_CPI=m +CONFIG_S390_TAPE=m + +# +# S/390 tape interface support +# +CONFIG_S390_TAPE_BLOCK=y + +# +# S/390 tape hardware support +# +CONFIG_S390_TAPE_34XX=m +# CONFIG_S390_TAPE_3590 is not set +# CONFIG_VMLOGRDR is not set +# CONFIG_VMCP is not set +# CONFIG_MONREADER is not set +CONFIG_MONWRITER=m + +# # File systems # CONFIG_EXT2_FS=y @@ -628,6 +647,7 @@ CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set @@ -658,6 +678,7 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SUN_PARTITION is not set # CONFIG_KARMA_PARTITION is not set # CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set # # Native Language Support @@ -668,8 +689,6 @@ CONFIG_MSDOS_PARTITION=y # Distributed Lock Manager # CONFIG_DLM=m -CONFIG_DLM_TCP=y -# CONFIG_DLM_SCTP is not set # CONFIG_DLM_DEBUG is not set # @@ -693,7 +712,6 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y CONFIG_HEADERS_CHECK=y CONFIG_DEBUG_KERNEL=y -CONFIG_LOG_BUF_SHIFT=17 # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set # CONFIG_DEBUG_SLAB is not set @@ -729,12 +747,13 @@ CONFIG_FORCED_INLINING=y CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_HASH=m CONFIG_CRYPTO_MANAGER=y -# CONFIG_CRYPTO_HMAC is not set +CONFIG_CRYPTO_HMAC=m # CONFIG_CRYPTO_XCBC is not set # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set -# CONFIG_CRYPTO_MD5 is not set +CONFIG_CRYPTO_MD5=m # CONFIG_CRYPTO_SHA1 is not set # CONFIG_CRYPTO_SHA256 is not set # CONFIG_CRYPTO_SHA512 is not set @@ -745,6 +764,7 @@ CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_CRYPTD is not set # CONFIG_CRYPTO_DES is not set CONFIG_CRYPTO_FCRYPT=m # CONFIG_CRYPTO_BLOWFISH is not set @@ -771,6 +791,8 @@ CONFIG_CRYPTO_CAMELLIA=m # CONFIG_CRYPTO_DES_S390 is not set # CONFIG_CRYPTO_AES_S390 is not set CONFIG_S390_PRNG=m +CONFIG_ZCRYPT=m +# CONFIG_ZCRYPT_MONOLITHIC is not set # # Library routines diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index ba5d3167df0d..8e1ea1c40128 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -477,7 +477,7 @@ static int __init hypfs_init(void) goto fail_diag; } } - kset_set_kset_s(&s390_subsys, hypervisor_subsys); + kobj_set_kset_s(&s390_subsys, hypervisor_subsys); rc = subsystem_register(&s390_subsys); if (rc) goto fail_sysfs; diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 0ea048d350d8..367caf92ea78 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -816,23 +816,23 @@ static int __init ipl_register_fcp_files(void) { int rc; - rc = sysfs_create_group(&ipl_subsys.kset.kobj, + rc = sysfs_create_group(&ipl_subsys.kobj, &ipl_fcp_attr_group); if (rc) goto out; - rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj, + rc = sysfs_create_bin_file(&ipl_subsys.kobj, &ipl_parameter_attr); if (rc) goto out_ipl_parm; - rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj, + rc = sysfs_create_bin_file(&ipl_subsys.kobj, &ipl_scp_data_attr); if (!rc) goto out; - sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr); + sysfs_remove_bin_file(&ipl_subsys.kobj, &ipl_parameter_attr); out_ipl_parm: - sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group); + sysfs_remove_group(&ipl_subsys.kobj, &ipl_fcp_attr_group); out: return rc; } @@ -846,7 +846,7 @@ static int __init ipl_init(void) return rc; switch (ipl_info.type) { case IPL_TYPE_CCW: - rc = sysfs_create_group(&ipl_subsys.kset.kobj, + rc = sysfs_create_group(&ipl_subsys.kobj, &ipl_ccw_attr_group); break; case IPL_TYPE_FCP: @@ -854,11 +854,11 @@ static int __init ipl_init(void) rc = ipl_register_fcp_files(); break; case IPL_TYPE_NSS: - rc = sysfs_create_group(&ipl_subsys.kset.kobj, + rc = sysfs_create_group(&ipl_subsys.kobj, &ipl_nss_attr_group); break; default: - rc = sysfs_create_group(&ipl_subsys.kset.kobj, + rc = sysfs_create_group(&ipl_subsys.kobj, &ipl_unknown_attr_group); break; } @@ -885,7 +885,7 @@ static int __init reipl_nss_init(void) if (!MACHINE_IS_VM) return 0; - rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group); + rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_nss_attr_group); if (rc) return rc; strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); @@ -900,7 +900,7 @@ static int __init reipl_ccw_init(void) reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); if (!reipl_block_ccw) return -ENOMEM; - rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group); + rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_ccw_attr_group); if (rc) { free_page((unsigned long)reipl_block_ccw); return rc; @@ -938,7 +938,7 @@ static int __init reipl_fcp_init(void) reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); if (!reipl_block_fcp) return -ENOMEM; - rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group); + rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_fcp_attr_group); if (rc) { free_page((unsigned long)reipl_block_fcp); return rc; @@ -990,7 +990,7 @@ static int __init dump_ccw_init(void) dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); if (!dump_block_ccw) return -ENOMEM; - rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group); + rc = sysfs_create_group(&dump_subsys.kobj, &dump_ccw_attr_group); if (rc) { free_page((unsigned long)dump_block_ccw); return rc; @@ -1014,7 +1014,7 @@ static int __init dump_fcp_init(void) dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); if (!dump_block_fcp) return -ENOMEM; - rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group); + rc = sysfs_create_group(&dump_subsys.kobj, &dump_fcp_attr_group); if (rc) { free_page((unsigned long)dump_block_fcp); return rc; diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 8b924b359774..d855cdbf8fb8 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -253,7 +253,10 @@ static int signal_return(struct mm_struct *mm, struct pt_regs *regs, unsigned long address, unsigned long error_code) { u16 instruction; - int rc, compat; + int rc; +#ifdef CONFIG_COMPAT + int compat; +#endif pagefault_disable(); rc = __get_user(instruction, (u16 __user *) regs->psw.addr); diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index d85e1ed7c3e4..cf9a75112d0f 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -377,7 +377,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, const char *type; u32 class; - dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); + dev = alloc_pci_dev(); if (!dev) return NULL; diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 76faaa8135dd..f974fefc3ebc 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -14,6 +14,200 @@ #include <asm/oplib.h> #include "pci_impl.h" +#include "pci_sun4v.h" + +static int config_out_of_range(struct pci_pbm_info *pbm, + unsigned long bus, + unsigned long devfn, + unsigned long reg) +{ + if (bus < pbm->pci_first_busno || + bus > pbm->pci_last_busno) + return 1; + return 0; +} + +static void *sun4u_config_mkaddr(struct pci_pbm_info *pbm, + unsigned long bus, + unsigned long devfn, + unsigned long reg) +{ + unsigned long rbits = pbm->config_space_reg_bits; + + if (config_out_of_range(pbm, bus, devfn, reg)) + return NULL; + + reg = (reg & ((1 << rbits) - 1)); + devfn <<= rbits; + bus <<= rbits + 8; + + return (void *) (pbm->config_space | bus | devfn | reg); +} + +static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, + int where, int size, u32 *value) +{ + struct pci_pbm_info *pbm = bus_dev->sysdata; + unsigned char bus = bus_dev->number; + u32 *addr; + u16 tmp16; + u8 tmp8; + + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, + size, value); + + switch (size) { + case 1: + *value = 0xff; + break; + case 2: + *value = 0xffff; + break; + case 4: + *value = 0xffffffff; + break; + } + + addr = sun4u_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + switch (size) { + case 1: + pci_config_read8((u8 *)addr, &tmp8); + *value = (u32) tmp8; + break; + + case 2: + if (where & 0x01) { + printk("pci_read_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_read16((u16 *)addr, &tmp16); + *value = (u32) tmp16; + break; + + case 4: + if (where & 0x03) { + printk("pci_read_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_read32(addr, value); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, + int where, int size, u32 value) +{ + struct pci_pbm_info *pbm = bus_dev->sysdata; + unsigned char bus = bus_dev->number; + u32 *addr; + + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, + size, value); + addr = sun4u_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + switch (size) { + case 1: + pci_config_write8((u8 *)addr, value); + break; + + case 2: + if (where & 0x01) { + printk("pci_write_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_write16((u16 *)addr, value); + break; + + case 4: + if (where & 0x03) { + printk("pci_write_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_write32(addr, value); + } + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops sun4u_pci_ops = { + .read = sun4u_read_pci_cfg, + .write = sun4u_write_pci_cfg, +}; + +static int sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, + int where, int size, u32 *value) +{ + struct pci_pbm_info *pbm = bus_dev->sysdata; + u32 devhandle = pbm->devhandle; + unsigned int bus = bus_dev->number; + unsigned int device = PCI_SLOT(devfn); + unsigned int func = PCI_FUNC(devfn); + unsigned long ret; + + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, + size, value); + if (config_out_of_range(pbm, bus, devfn, where)) { + ret = ~0UL; + } else { + ret = pci_sun4v_config_get(devhandle, + HV_PCI_DEVICE_BUILD(bus, device, func), + where, size); + } + switch (size) { + case 1: + *value = ret & 0xff; + break; + case 2: + *value = ret & 0xffff; + break; + case 4: + *value = ret & 0xffffffff; + break; + }; + + + return PCIBIOS_SUCCESSFUL; +} + +static int sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, + int where, int size, u32 value) +{ + struct pci_pbm_info *pbm = bus_dev->sysdata; + u32 devhandle = pbm->devhandle; + unsigned int bus = bus_dev->number; + unsigned int device = PCI_SLOT(devfn); + unsigned int func = PCI_FUNC(devfn); + unsigned long ret; + + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, + size, value); + if (config_out_of_range(pbm, bus, devfn, where)) { + /* Do nothing. */ + } else { + ret = pci_sun4v_config_put(devhandle, + HV_PCI_DEVICE_BUILD(bus, device, func), + where, size, value); + } + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops sun4v_pci_ops = { + .read = sun4v_read_pci_cfg, + .write = sun4v_write_pci_cfg, +}; void pci_get_pbm_props(struct pci_pbm_info *pbm) { diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c index 2e0eb4ee8f71..9198c1a0f7a5 100644 --- a/arch/sparc64/kernel/pci_fire.c +++ b/arch/sparc64/kernel/pci_fire.c @@ -27,138 +27,6 @@ "i" (ASI_PHYS_BYPASS_EC_E) \ : "memory") -/* Fire config space address format is nearly identical to - * that of SCHIZO and PSYCHO, except that in order to accomodate - * PCI-E extended config space the encoding can handle 12 bits - * of register address: - * - * 32 28 27 20 19 15 14 12 11 2 1 0 - * ------------------------------------------------- - * |0 0 0 0 0| bus | device | function | reg | 0 0 | - * ------------------------------------------------- - */ -#define FIRE_CONFIG_BASE(PBM) ((PBM)->config_space) -#define FIRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ - (((unsigned long)(BUS) << 20) | \ - ((unsigned long)(DEVFN) << 12) | \ - ((unsigned long)(REG))) - -static void *fire_pci_config_mkaddr(struct pci_pbm_info *pbm, - unsigned char bus, - unsigned int devfn, - int where) -{ - if (!pbm) - return NULL; - return (void *) - (FIRE_CONFIG_BASE(pbm) | - FIRE_CONFIG_ENCODE(bus, devfn, where)); -} - -/* FIRE PCI configuration space accessors. */ - -static int fire_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 *value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - unsigned char bus = bus_dev->number; - u32 *addr; - u16 tmp16; - u8 tmp8; - - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, - size, value); - switch (size) { - case 1: - *value = 0xff; - break; - case 2: - *value = 0xffff; - break; - case 4: - *value = 0xffffffff; - break; - } - - addr = fire_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - switch (size) { - case 1: - pci_config_read8((u8 *)addr, &tmp8); - *value = tmp8; - break; - - case 2: - if (where & 0x01) { - printk("pci_read_config_word: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_read16((u16 *)addr, &tmp16); - *value = tmp16; - break; - - case 4: - if (where & 0x03) { - printk("pci_read_config_dword: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - - pci_config_read32(addr, value); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int fire_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - unsigned char bus = bus_dev->number; - u32 *addr; - - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, - size, value); - addr = fire_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - switch (size) { - case 1: - pci_config_write8((u8 *)addr, value); - break; - - case 2: - if (where & 0x01) { - printk("pci_write_config_word: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_write16((u16 *)addr, value); - break; - - case 4: - if (where & 0x03) { - printk("pci_write_config_dword: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - - pci_config_write32(addr, value); - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops pci_fire_ops = { - .read = fire_read_pci_cfg, - .write = fire_write_pci_cfg, -}; - static void pci_fire_scan_bus(struct pci_pbm_info *pbm) { pbm->pci_bus = pci_scan_one_pbm(pbm); @@ -314,7 +182,8 @@ static void pci_fire_pbm_init(struct pci_controller_info *p, pci_pbm_root = pbm; pbm->scan_bus = pci_fire_scan_bus; - pbm->pci_ops = &pci_fire_ops; + pbm->pci_ops = &sun4u_pci_ops; + pbm->config_space_reg_bits = 12; pbm->index = pci_num_pbms++; diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index 8e38023868aa..f660c2b685eb 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -77,6 +77,9 @@ struct pci_pbm_info { /* Base of PCI Config space, can be per-PBM or shared. */ unsigned long config_space; + /* This will be 12 on PCI-E controllers, 8 elsewhere. */ + unsigned long config_space_reg_bits; + /* State of 66MHz capabilities on this PBM. */ int is_66mhz_capable; int all_devs_66mhz; @@ -156,4 +159,7 @@ extern void pci_config_write8(u8 *addr, u8 val); extern void pci_config_write16(u16 *addr, u16 val); extern void pci_config_write32(u32 *addr, u32 val); +extern struct pci_ops sun4u_pci_ops; +extern struct pci_ops sun4v_pci_ops; + #endif /* !(PCI_IMPL_H) */ diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 2edcb1dd13c3..598393a2df16 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -94,122 +94,6 @@ static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm, PSYCHO_CONFIG_ENCODE(bus, devfn, where)); } -static int psycho_out_of_range(struct pci_pbm_info *pbm, - unsigned char bus, - unsigned char devfn) -{ - return ((bus == pbm->pci_first_busno) && - PCI_SLOT(devfn) > 8); -} - -/* PSYCHO PCI configuration space accessors. */ - -static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 *value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - unsigned char bus = bus_dev->number; - u32 *addr; - u16 tmp16; - u8 tmp8; - - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, - size, value); - - switch (size) { - case 1: - *value = 0xff; - break; - case 2: - *value = 0xffff; - break; - case 4: - *value = 0xffffffff; - break; - } - - addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (psycho_out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - switch (size) { - case 1: - pci_config_read8((u8 *)addr, &tmp8); - *value = (u32) tmp8; - break; - - case 2: - if (where & 0x01) { - printk("pci_read_config_word: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_read16((u16 *)addr, &tmp16); - *value = (u32) tmp16; - break; - - case 4: - if (where & 0x03) { - printk("pci_read_config_dword: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_read32(addr, value); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - unsigned char bus = bus_dev->number; - u32 *addr; - - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, - size, value); - addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (psycho_out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - switch (size) { - case 1: - pci_config_write8((u8 *)addr, value); - break; - - case 2: - if (where & 0x01) { - printk("pci_write_config_word: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_write16((u16 *)addr, value); - break; - - case 4: - if (where & 0x03) { - printk("pci_write_config_dword: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_write32(addr, value); - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops psycho_ops = { - .read = psycho_read_pci_cfg, - .write = psycho_write_pci_cfg, -}; - /* PSYCHO error handling support. */ enum psycho_error_type { UE_ERR, CE_ERR, PCI_ERR @@ -1089,7 +973,8 @@ static void psycho_pbm_init(struct pci_controller_info *p, pci_pbm_root = pbm; pbm->scan_bus = psycho_scan_bus; - pbm->pci_ops = &psycho_ops; + pbm->pci_ops = &sun4u_pci_ops; + pbm->config_space_reg_bits = 8; pbm->index = pci_num_pbms++; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 4cefe6e83b24..e2377796de89 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -205,294 +205,9 @@ #define SABRE_MEMSPACE 0x100000000UL #define SABRE_MEMSPACE_SIZE 0x07fffffffUL -/* UltraSparc-IIi Programmer's Manual, page 325, PCI - * configuration space address format: - * - * 32 24 23 16 15 11 10 8 7 2 1 0 - * --------------------------------------------------------- - * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 | - * --------------------------------------------------------- - */ -#define SABRE_CONFIG_BASE(PBM) \ - ((PBM)->config_space | (1UL << 24)) -#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ - (((unsigned long)(BUS) << 16) | \ - ((unsigned long)(DEVFN) << 8) | \ - ((unsigned long)(REG))) - static int hummingbird_p; static struct pci_bus *sabre_root_bus; -static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm, - unsigned char bus, - unsigned int devfn, - int where) -{ - if (!pbm) - return NULL; - return (void *) - (SABRE_CONFIG_BASE(pbm) | - SABRE_CONFIG_ENCODE(bus, devfn, where)); -} - -static int sabre_out_of_range(unsigned char devfn) -{ - if (hummingbird_p) - return 0; - - return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) || - ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) || - (PCI_SLOT(devfn) > 1)); -} - -static int __sabre_out_of_range(struct pci_pbm_info *pbm, - unsigned char bus, - unsigned char devfn) -{ - if (hummingbird_p) - return 0; - - return ((pbm->parent == 0) || - ((pbm == &pbm->parent->pbm_A) && - (bus == pbm->pci_first_busno) && - PCI_SLOT(devfn) > 8)); -} - -static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 *value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - unsigned char bus = bus_dev->number; - u32 *addr; - u16 tmp16; - u8 tmp8; - - switch (size) { - case 1: - *value = 0xff; - break; - case 2: - *value = 0xffff; - break; - case 4: - *value = 0xffffffff; - break; - } - - addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (__sabre_out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - switch (size) { - case 1: - pci_config_read8((u8 *) addr, &tmp8); - *value = tmp8; - break; - - case 2: - if (where & 0x01) { - printk("pci_read_config_word: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_read16((u16 *) addr, &tmp16); - *value = tmp16; - break; - - case 4: - if (where & 0x03) { - printk("pci_read_config_dword: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_read32(addr, value); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *value) -{ - struct pci_pbm_info *pbm = bus->sysdata; - - if (bus == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus, devfn, where, - size, value); - - if (!bus->number && sabre_out_of_range(devfn)) { - switch (size) { - case 1: - *value = 0xff; - break; - case 2: - *value = 0xffff; - break; - case 4: - *value = 0xffffffff; - break; - } - return PCIBIOS_SUCCESSFUL; - } - - if (bus->number || PCI_SLOT(devfn)) - return __sabre_read_pci_cfg(bus, devfn, where, size, value); - - /* When accessing PCI config space of the PCI controller itself (bus - * 0, device slot 0, function 0) there are restrictions. Each - * register must be accessed as it's natural size. Thus, for example - * the Vendor ID must be accessed as a 16-bit quantity. - */ - - switch (size) { - case 1: - if (where < 8) { - u32 tmp32; - u16 tmp16; - - __sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32); - tmp16 = (u16) tmp32; - if (where & 1) - *value = tmp16 >> 8; - else - *value = tmp16 & 0xff; - } else - return __sabre_read_pci_cfg(bus, devfn, where, 1, value); - break; - - case 2: - if (where < 8) - return __sabre_read_pci_cfg(bus, devfn, where, 2, value); - else { - u32 tmp32; - u8 tmp8; - - __sabre_read_pci_cfg(bus, devfn, where, 1, &tmp32); - tmp8 = (u8) tmp32; - *value = tmp8; - __sabre_read_pci_cfg(bus, devfn, where + 1, 1, &tmp32); - tmp8 = (u8) tmp32; - *value |= tmp8 << 8; - } - break; - - case 4: { - u32 tmp32; - u16 tmp16; - - sabre_read_pci_cfg(bus, devfn, where, 2, &tmp32); - tmp16 = (u16) tmp32; - *value = tmp16; - sabre_read_pci_cfg(bus, devfn, where + 2, 2, &tmp32); - tmp16 = (u16) tmp32; - *value |= tmp16 << 16; - break; - } - } - return PCIBIOS_SUCCESSFUL; -} - -static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - unsigned char bus = bus_dev->number; - u32 *addr; - - addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (__sabre_out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - switch (size) { - case 1: - pci_config_write8((u8 *) addr, value); - break; - - case 2: - if (where & 0x01) { - printk("pci_write_config_word: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_write16((u16 *) addr, value); - break; - - case 4: - if (where & 0x03) { - printk("pci_write_config_dword: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_write32(addr, value); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 value) -{ - struct pci_pbm_info *pbm = bus->sysdata; - - if (bus == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus, devfn, where, - size, value); - - if (bus->number) - return __sabre_write_pci_cfg(bus, devfn, where, size, value); - - if (sabre_out_of_range(devfn)) - return PCIBIOS_SUCCESSFUL; - - switch (size) { - case 1: - if (where < 8) { - u32 tmp32; - u16 tmp16; - - __sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32); - tmp16 = (u16) tmp32; - if (where & 1) { - value &= 0x00ff; - value |= tmp16 << 8; - } else { - value &= 0xff00; - value |= tmp16; - } - tmp32 = (u32) tmp16; - return __sabre_write_pci_cfg(bus, devfn, where & ~1, 2, tmp32); - } else - return __sabre_write_pci_cfg(bus, devfn, where, 1, value); - break; - case 2: - if (where < 8) - return __sabre_write_pci_cfg(bus, devfn, where, 2, value); - else { - __sabre_write_pci_cfg(bus, devfn, where, 1, value & 0xff); - __sabre_write_pci_cfg(bus, devfn, where + 1, 1, value >> 8); - } - break; - case 4: - sabre_write_pci_cfg(bus, devfn, where, 2, value & 0xffff); - sabre_write_pci_cfg(bus, devfn, where + 2, 2, value >> 16); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops sabre_ops = { - .read = sabre_read_pci_cfg, - .write = sabre_write_pci_cfg, -}; - /* SABRE error handling support. */ static void sabre_check_iommu_error(struct pci_pbm_info *pbm, unsigned long afsr, @@ -1010,7 +725,8 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *p printk("%s: SABRE PCI Bus Module\n", pbm->name); pbm->scan_bus = sabre_scan_bus; - pbm->pci_ops = &sabre_ops; + pbm->pci_ops = &sun4u_pci_ops; + pbm->config_space_reg_bits = 8; pbm->index = pci_num_pbms++; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index e375d72b8eed..ae76898bbe2b 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -104,125 +104,6 @@ static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm, SCHIZO_CONFIG_ENCODE(bus, devfn, where)); } -/* Just make sure the bus number is in range. */ -static int schizo_out_of_range(struct pci_pbm_info *pbm, - unsigned char bus, - unsigned char devfn) -{ - if (bus < pbm->pci_first_busno || - bus > pbm->pci_last_busno) - return 1; - return 0; -} - -/* SCHIZO PCI configuration space accessors. */ - -static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 *value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - unsigned char bus = bus_dev->number; - u32 *addr; - u16 tmp16; - u8 tmp8; - - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, - size, value); - switch (size) { - case 1: - *value = 0xff; - break; - case 2: - *value = 0xffff; - break; - case 4: - *value = 0xffffffff; - break; - } - - addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (schizo_out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - switch (size) { - case 1: - pci_config_read8((u8 *)addr, &tmp8); - *value = tmp8; - break; - - case 2: - if (where & 0x01) { - printk("pci_read_config_word: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_read16((u16 *)addr, &tmp16); - *value = tmp16; - break; - - case 4: - if (where & 0x03) { - printk("pci_read_config_dword: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_read32(addr, value); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - unsigned char bus = bus_dev->number; - u32 *addr; - - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, - size, value); - addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (schizo_out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - switch (size) { - case 1: - pci_config_write8((u8 *)addr, value); - break; - - case 2: - if (where & 0x01) { - printk("pci_write_config_word: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - pci_config_write16((u16 *)addr, value); - break; - - case 4: - if (where & 0x03) { - printk("pci_write_config_dword: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - - pci_config_write32(addr, value); - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops schizo_ops = { - .read = schizo_read_pci_cfg, - .write = schizo_write_pci_cfg, -}; - /* SCHIZO error handling support. */ enum schizo_error_type { UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR @@ -1494,7 +1375,8 @@ static void schizo_pbm_init(struct pci_controller_info *p, pci_pbm_root = pbm; pbm->scan_bus = schizo_scan_bus; - pbm->pci_ops = &schizo_ops; + pbm->pci_ops = &sun4u_pci_ops; + pbm->config_space_reg_bits = 8; pbm->index = pci_num_pbms++; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 0c76a8891a96..34df4047587a 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -593,89 +593,6 @@ const struct pci_iommu_ops pci_sun4v_iommu_ops = { .dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu, }; -static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func) -{ - if (bus < pbm->pci_first_busno || - bus > pbm->pci_last_busno) - return 1; - return 0; -} - -static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 *value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - u32 devhandle = pbm->devhandle; - unsigned int bus = bus_dev->number; - unsigned int device = PCI_SLOT(devfn); - unsigned int func = PCI_FUNC(devfn); - unsigned long ret; - - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, - size, value); - if (pci_sun4v_out_of_range(pbm, bus, device, func)) { - ret = ~0UL; - } else { - ret = pci_sun4v_config_get(devhandle, - HV_PCI_DEVICE_BUILD(bus, device, func), - where, size); -#if 0 - printk("rcfg: [%x:%x:%x:%d]=[%lx]\n", - devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), - where, size, ret); -#endif - } - switch (size) { - case 1: - *value = ret & 0xff; - break; - case 2: - *value = ret & 0xffff; - break; - case 4: - *value = ret & 0xffffffff; - break; - }; - - - return PCIBIOS_SUCCESSFUL; -} - -static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, - int where, int size, u32 value) -{ - struct pci_pbm_info *pbm = bus_dev->sysdata; - u32 devhandle = pbm->devhandle; - unsigned int bus = bus_dev->number; - unsigned int device = PCI_SLOT(devfn); - unsigned int func = PCI_FUNC(devfn); - unsigned long ret; - - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, - size, value); - if (pci_sun4v_out_of_range(pbm, bus, device, func)) { - /* Do nothing. */ - } else { - ret = pci_sun4v_config_put(devhandle, - HV_PCI_DEVICE_BUILD(bus, device, func), - where, size, value); -#if 0 - printk("wcfg: [%x:%x:%x:%d] v[%x] == [%lx]\n", - devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), - where, size, value, ret); -#endif - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops pci_sun4v_ops = { - .read = pci_sun4v_read_pci_cfg, - .write = pci_sun4v_write_pci_cfg, -}; - - static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm) { struct property *prop; @@ -1238,7 +1155,8 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pci_pbm_root = pbm; pbm->scan_bus = pci_sun4v_scan_bus; - pbm->pci_ops = &pci_sun4v_ops; + pbm->pci_ops = &sun4v_pci_ops; + pbm->config_space_reg_bits = 12; pbm->index = pci_num_pbms++; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index c54d4d8af014..b7976b14d0ba 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -1636,10 +1636,21 @@ static struct device_node * __init create_node(phandle node, struct device_node static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp) { + struct device_node *ret = NULL, *prev_sibling = NULL; struct device_node *dp; - dp = create_node(node, parent); - if (dp) { + while (1) { + dp = create_node(node, parent); + if (!dp) + break; + + if (prev_sibling) + prev_sibling->sibling = dp; + + if (!ret) + ret = dp; + prev_sibling = dp; + *(*nextp) = dp; *nextp = &dp->allnext; @@ -1648,10 +1659,10 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl dp->child = build_tree(dp, prom_getchild(node), nextp); - dp->sibling = build_tree(parent, prom_getsibling(node), nextp); + node = prom_getsibling(node); } - return dp; + return ret; } void __init prom_build_devicetree(void) diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 8c2ac41187c1..d28f01379b9b 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -778,6 +778,7 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs) return; if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0) == NOTIFY_STOP) + return; if (!do_nmi_callback(regs,cpu)) unknown_nmi_error(reason, regs); diff --git a/drivers/Makefile b/drivers/Makefile index 26ca9031ea49..adad2f3d438a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_FC4) += fc4/ obj-$(CONFIG_SCSI) += scsi/ obj-$(CONFIG_ATA) += ata/ obj-$(CONFIG_FUSION) += message/ +obj-$(CONFIG_FIREWIRE) += firewire/ obj-$(CONFIG_IEEE1394) += ieee1394/ obj-y += cdrom/ obj-y += auxdisplay/ diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 1683e5c5b94c..1cbe61905824 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -231,8 +231,10 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, * Obtain the method mutex if necessary. Do not acquire mutex for a * recursive call. */ - if (acpi_os_get_thread_id() != - obj_desc->method.mutex->mutex.owner_thread_id) { + if (!walk_state || + !obj_desc->method.mutex->mutex.owner_thread || + (walk_state->thread != + obj_desc->method.mutex->mutex.owner_thread)) { /* * Acquire the method mutex. This releases the interpreter if we * block (and reacquires it before it returns) @@ -246,14 +248,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, } /* Update the mutex and walk info and save the original sync_level */ - obj_desc->method.mutex->mutex.owner_thread_id = - acpi_os_get_thread_id(); if (walk_state) { obj_desc->method.mutex->mutex. original_sync_level = walk_state->thread->current_sync_level; + obj_desc->method.mutex->mutex.owner_thread = + walk_state->thread; walk_state->thread->current_sync_level = obj_desc->method.sync_level; } else { @@ -567,7 +569,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, acpi_os_release_mutex(method_desc->method.mutex->mutex. os_mutex); - method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; + method_desc->method.mutex->mutex.owner_thread = NULL; } } diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index 6c6104a7a247..fc9da4879cbf 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -866,8 +866,7 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) && (op->common.parent->common.aml_opcode != AML_VAR_PACKAGE_OP) - && (op->common.parent->common.aml_opcode != - AML_NAME_OP))) { + && (op->common.parent->common.aml_opcode != AML_NAME_OP))) { walk_state->result_obj = obj_desc; } } diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index e4073e05a75c..71503c036f7c 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -556,10 +556,9 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, * indicate this to the interpreter, set the * object to the root */ - obj_desc = - ACPI_CAST_PTR(union - acpi_operand_object, - acpi_gbl_root_node); + obj_desc = ACPI_CAST_PTR(union + acpi_operand_object, + acpi_gbl_root_node); status = AE_OK; } else { /* diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index 16c8e38b51ef..5afcdd9c7449 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -630,12 +630,9 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread) * ******************************************************************************/ -struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, - union acpi_parse_object - *origin, - union acpi_operand_object - *method_desc, - struct acpi_thread_state +struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object + *origin, union acpi_operand_object + *method_desc, struct acpi_thread_state *thread) { struct acpi_walk_state *walk_state; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e08cf98f504f..82f496c07675 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -147,9 +147,10 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event, return 0; } -static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count) +static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, + unsigned count, int force_poll) { - if (acpi_ec_mode == EC_POLL) { + if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) { unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); while (time_before(jiffies, delay)) { if (acpi_ec_check_status(ec, event, 0)) @@ -173,14 +174,15 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count) static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, const u8 * wdata, unsigned wdata_len, - u8 * rdata, unsigned rdata_len) + u8 * rdata, unsigned rdata_len, + int force_poll) { int result = 0; unsigned count = atomic_read(&ec->event_count); acpi_ec_write_cmd(ec, command); for (; wdata_len > 0; --wdata_len) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll); if (result) { printk(KERN_ERR PREFIX "write_cmd timeout, command = %d\n", command); @@ -191,7 +193,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, } if (!rdata_len) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll); if (result) { printk(KERN_ERR PREFIX "finish-write timeout, command = %d\n", command); @@ -202,7 +204,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, } for (; rdata_len > 0; --rdata_len) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count); + result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count, force_poll); if (result) { printk(KERN_ERR PREFIX "read timeout, command = %d\n", command); @@ -217,7 +219,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, const u8 * wdata, unsigned wdata_len, - u8 * rdata, unsigned rdata_len) + u8 * rdata, unsigned rdata_len, + int force_poll) { int status; u32 glk; @@ -240,7 +243,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, /* Make sure GPE is enabled before doing transaction */ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0); if (status) { printk(KERN_DEBUG PREFIX "input buffer is not empty, aborting transaction\n"); @@ -249,7 +252,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, status = acpi_ec_transaction_unlocked(ec, command, wdata, wdata_len, - rdata, rdata_len); + rdata, rdata_len, + force_poll); end: @@ -267,12 +271,12 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, int acpi_ec_burst_enable(struct acpi_ec *ec) { u8 d; - return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1); + return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0); } int acpi_ec_burst_disable(struct acpi_ec *ec) { - return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0); + return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0); } static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) @@ -281,7 +285,7 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) u8 d; result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ, - &address, 1, &d, 1); + &address, 1, &d, 1, 0); *data = d; return result; } @@ -290,7 +294,7 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) { u8 wdata[2] = { address, data }; return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, - wdata, 2, NULL, 0); + wdata, 2, NULL, 0, 0); } /* @@ -349,13 +353,15 @@ EXPORT_SYMBOL(ec_write); int ec_transaction(u8 command, const u8 * wdata, unsigned wdata_len, - u8 * rdata, unsigned rdata_len) + u8 * rdata, unsigned rdata_len, + int force_poll) { if (!first_ec) return -ENODEV; return acpi_ec_transaction(first_ec, command, wdata, - wdata_len, rdata, rdata_len); + wdata_len, rdata, rdata_len, + force_poll); } EXPORT_SYMBOL(ec_transaction); @@ -374,7 +380,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) * bit to be cleared (and thus clearing the interrupt source). */ - result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1); + result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0); if (result) return result; @@ -410,6 +416,7 @@ static u32 acpi_ec_gpe_handler(void *data) acpi_status status = AE_OK; u8 value; struct acpi_ec *ec = data; + atomic_inc(&ec->event_count); if (acpi_ec_mode == EC_INTR) { diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 635ba449ebc2..e22f4a973c0f 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -341,9 +341,8 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, /* A Non-NULL gpe_device means this is a GPE Block Device */ - obj_desc = - acpi_ns_get_attached_object((struct acpi_namespace_node *) - gpe_device); + obj_desc = acpi_ns_get_attached_object((struct acpi_namespace_node *) + gpe_device); if (!obj_desc || !obj_desc->device.gpe_block) { return (NULL); } diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index ad5bc76edf46..902c287b3a4f 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -1033,8 +1033,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) - && (gpe_event_info-> - flags & ACPI_GPE_TYPE_RUNTIME)) { + && (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) { gpe_enabled_count++; } diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index cae786ca8600..21cb749d0c75 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -196,15 +196,12 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, notify_info->notify.value = (u16) notify_value; notify_info->notify.handler_obj = handler_obj; - acpi_ex_exit_interpreter(); - - acpi_ev_notify_dispatch(notify_info); - - status = acpi_ex_enter_interpreter(); + status = + acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, + notify_info); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + acpi_ut_delete_generic_state(notify_info); } - } if (!handler_obj) { @@ -323,8 +320,9 @@ static u32 acpi_ev_global_lock_handler(void *context) acpi_gbl_global_lock_acquired = TRUE; /* Send a unit to the semaphore */ - if (ACPI_FAILURE(acpi_os_signal_semaphore( - acpi_gbl_global_lock_semaphore, 1))) { + if (ACPI_FAILURE + (acpi_os_signal_semaphore + (acpi_gbl_global_lock_semaphore, 1))) { ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore")); } @@ -450,7 +448,9 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) } if (ACPI_FAILURE(status)) { - status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout); + status = + acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, + timeout); } if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 96b0e8431748..e99f0c435a47 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -291,7 +291,6 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 bit_width, acpi_integer * value) { acpi_status status; - acpi_status status2; acpi_adr_space_handler handler; acpi_adr_space_setup region_setup; union acpi_operand_object *handler_desc; @@ -345,7 +344,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, * setup will potentially execute control methods * (e.g., _REG method for this region) */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); status = region_setup(region_obj, ACPI_REGION_ACTIVATE, handler_desc->address_space.context, @@ -353,10 +352,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* Re-enter the interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); /* Check for failure of the Region Setup */ @@ -409,7 +405,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, * exit the interpreter because the handler *might* block -- we don't * know what it will do, so we can't hold the lock on the intepreter. */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); } /* Call the handler */ @@ -430,10 +426,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, * We just returned from a non-default handler, we must re-enter the * interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); } return_ACPI_STATUS(status); diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index a4fa7e6822a3..400d90fca966 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -228,7 +228,8 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, /* Install a handler for this PCI root bridge */ - status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); + status = + acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); if (ACPI_FAILURE(status)) { if (status == AE_SAME_HANDLER) { /* diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index a3379bafa676..6d866a01f5f4 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -91,7 +91,6 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler) ACPI_EXPORT_SYMBOL(acpi_install_exception_handler) #endif /* ACPI_FUTURE_USAGE */ - /******************************************************************************* * * FUNCTION: acpi_install_fixed_event_handler @@ -768,11 +767,9 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle) return (AE_BAD_PARAMETER); } - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return (status); - } + /* Must lock interpreter to prevent race conditions */ + acpi_ex_enter_interpreter(); status = acpi_ev_acquire_global_lock(timeout); acpi_ex_exit_interpreter(); diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index 17065e98807c..9cbd3414a574 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -472,7 +472,6 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) } ACPI_EXPORT_SYMBOL(acpi_clear_gpe) - #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -568,7 +567,6 @@ acpi_get_gpe_status(acpi_handle gpe_device, ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) #endif /* ACPI_FUTURE_USAGE */ - /******************************************************************************* * * FUNCTION: acpi_install_gpe_block diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index d470e8b1f4ea..79f2c0d42c06 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -512,9 +512,8 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc, * Create a new string object and string buffer * (-1 because of extra separator included in string_length from above) */ - return_desc = - acpi_ut_create_string_object((acpi_size) - (string_length - 1)); + return_desc = acpi_ut_create_string_object((acpi_size) + (string_length - 1)); if (!return_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c index ae97812681a3..6e9a23e47fef 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/executer/excreate.c @@ -50,7 +50,6 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("excreate") - #ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* * @@ -583,10 +582,7 @@ acpi_ex_create_method(u8 * aml_start, * Get the sync_level. If method is serialized, a mutex will be * created for this method when it is parsed. */ - if (acpi_gbl_all_methods_serialized) { - obj_desc->method.sync_level = 0; - obj_desc->method.method_flags |= AML_METHOD_SERIALIZED; - } else if (method_flags & AML_METHOD_SERIALIZED) { + if (method_flags & AML_METHOD_SERIALIZED) { /* * ACPI 1.0: sync_level = 0 * ACPI 2.0: sync_level = sync_level in method declaration diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 1a73c14df2c5..51c9c29987c3 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -134,7 +134,7 @@ static struct acpi_exdump_info acpi_ex_dump_method[8] = { static struct acpi_exdump_info acpi_ex_dump_mutex[5] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"}, - {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread_id), "Owner Thread"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"}, {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth), "Acquire Depth"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"} @@ -451,9 +451,8 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) ACPI_FUNCTION_NAME(ex_dump_operand) - if (! - ((ACPI_LV_EXEC & acpi_dbg_level) - && (_COMPONENT & acpi_dbg_layer))) { + if (!((ACPI_LV_EXEC & acpi_dbg_level) + && (_COMPONENT & acpi_dbg_layer))) { return; } @@ -844,9 +843,8 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags) ACPI_FUNCTION_ENTRY(); if (!flags) { - if (! - ((ACPI_LV_OBJECTS & acpi_dbg_level) - && (_COMPONENT & acpi_dbg_layer))) { + if (!((ACPI_LV_OBJECTS & acpi_dbg_level) + && (_COMPONENT & acpi_dbg_layer))) { return; } } @@ -1011,9 +1009,8 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags) } if (!flags) { - if (! - ((ACPI_LV_OBJECTS & acpi_dbg_level) - && (_COMPONENT & acpi_dbg_layer))) { + if (!((ACPI_LV_OBJECTS & acpi_dbg_level) + && (_COMPONENT & acpi_dbg_layer))) { return_VOID; } } diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index 4eb883bda6ae..6748e3ef0997 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -66,9 +66,10 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc, * ******************************************************************************/ -void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc, - struct acpi_thread_state *thread) +void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) { + struct acpi_thread_state *thread = obj_desc->mutex.owner_thread; + if (!thread) { return; } @@ -173,13 +174,16 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, /* Support for multiple acquires by the owning thread */ - if (obj_desc->mutex.owner_thread_id == acpi_os_get_thread_id()) { - /* - * The mutex is already owned by this thread, just increment the - * acquisition depth - */ - obj_desc->mutex.acquisition_depth++; - return_ACPI_STATUS(AE_OK); + if (obj_desc->mutex.owner_thread) { + if (obj_desc->mutex.owner_thread->thread_id == + walk_state->thread->thread_id) { + /* + * The mutex is already owned by this thread, just increment the + * acquisition depth + */ + obj_desc->mutex.acquisition_depth++; + return_ACPI_STATUS(AE_OK); + } } /* Acquire the mutex, wait if necessary. Special case for Global Lock */ @@ -202,7 +206,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, /* Have the mutex: update mutex and walk info and save the sync_level */ - obj_desc->mutex.owner_thread_id = acpi_os_get_thread_id(); + obj_desc->mutex.owner_thread = walk_state->thread; obj_desc->mutex.acquisition_depth = 1; obj_desc->mutex.original_sync_level = walk_state->thread->current_sync_level; @@ -242,7 +246,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, /* The mutex must have been previously acquired in order to release it */ - if (!obj_desc->mutex.owner_thread_id) { + if (!obj_desc->mutex.owner_thread) { ACPI_ERROR((AE_INFO, "Cannot release Mutex [%4.4s], not acquired", acpi_ut_get_node_name(obj_desc->mutex.node))); @@ -262,14 +266,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, * The Mutex is owned, but this thread must be the owner. * Special case for Global Lock, any thread can release */ - if ((obj_desc->mutex.owner_thread_id != + if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", (unsigned long)walk_state->thread->thread_id, acpi_ut_get_node_name(obj_desc->mutex.node), - (unsigned long)obj_desc->mutex.owner_thread_id)); + (unsigned long)obj_desc->mutex.owner_thread-> + thread_id)); return_ACPI_STATUS(AE_AML_NOT_OWNER); } @@ -296,7 +301,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, /* Unlink the mutex from the owner's list */ - acpi_ex_unlink_mutex(obj_desc, walk_state->thread); + acpi_ex_unlink_mutex(obj_desc); /* Release the mutex, special case for Global Lock */ @@ -308,7 +313,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, /* Update the mutex and restore sync_level */ - obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; + obj_desc->mutex.owner_thread = NULL; walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level; @@ -363,7 +368,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) /* Mark mutex unowned */ - obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; + obj_desc->mutex.owner_thread = NULL; /* Update Thread sync_level (Last mutex is the important one) */ diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index 1ee4fb1175c6..308eae52dc05 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -177,8 +177,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Bytes from stream:\n")); - for (index = 0; - (index < ACPI_NAME_SIZE) + for (index = 0; (index < ACPI_NAME_SIZE) && (acpi_ut_valid_acpi_char(*aml_address, 0)); index++) { char_buf[index] = *aml_address++; ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "%c\n", char_buf[index])); diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c index a6696621ff1b..efe5d4b461a4 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/executer/exprep.c @@ -242,7 +242,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, obj_desc->common_field.bit_length, 0xFFFFFFFF /* Temp until we pass region_length as parameter */ - ); + ); bit_length = byte_alignment * 8; #endif diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c index ba761862a599..09d897b3f6d5 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/executer/exresop.c @@ -354,8 +354,7 @@ acpi_ex_resolve_operands(u16 opcode, if ((opcode == AML_STORE_OP) && (ACPI_GET_OBJECT_TYPE(*stack_ptr) == ACPI_TYPE_LOCAL_REFERENCE) - && ((*stack_ptr)->reference.opcode == - AML_INDEX_OP)) { + && ((*stack_ptr)->reference.opcode == AML_INDEX_OP)) { goto next_operand; } break; diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index b2edf620ba89..9460baff3032 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -66,7 +66,6 @@ ACPI_MODULE_NAME("exsystem") acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) { acpi_status status; - acpi_status status2; ACPI_FUNCTION_TRACE(ex_system_wait_semaphore); @@ -79,7 +78,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) /* We must wait, so unlock the interpreter */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); status = acpi_os_wait_semaphore(semaphore, 1, timeout); @@ -89,13 +88,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) /* Reacquire the interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - - /* Report fatal error, could not acquire interpreter */ - - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); } return_ACPI_STATUS(status); @@ -119,7 +112,6 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) { acpi_status status; - acpi_status status2; ACPI_FUNCTION_TRACE(ex_system_wait_mutex); @@ -132,7 +124,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) /* We must wait, so unlock the interpreter */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); status = acpi_os_acquire_mutex(mutex, timeout); @@ -142,13 +134,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) /* Reacquire the interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - - /* Report fatal error, could not acquire interpreter */ - - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); } return_ACPI_STATUS(status); @@ -209,20 +195,18 @@ acpi_status acpi_ex_system_do_stall(u32 how_long) acpi_status acpi_ex_system_do_suspend(acpi_integer how_long) { - acpi_status status; - ACPI_FUNCTION_ENTRY(); /* Since this thread will sleep, we must release the interpreter */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); acpi_os_sleep(how_long); /* And now we must get the interpreter again */ - status = acpi_ex_enter_interpreter(); - return (status); + acpi_ex_reacquire_interpreter(); + return (AE_OK); } /******************************************************************************* diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index aea461f3a48c..6b0aeccbb69b 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -76,14 +76,15 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base); * * PARAMETERS: None * - * RETURN: Status + * RETURN: None * - * DESCRIPTION: Enter the interpreter execution region. Failure to enter - * the interpreter region is a fatal system error + * DESCRIPTION: Enter the interpreter execution region. Failure to enter + * the interpreter region is a fatal system error. Used in + * conjunction with exit_interpreter. * ******************************************************************************/ -acpi_status acpi_ex_enter_interpreter(void) +void acpi_ex_enter_interpreter(void) { acpi_status status; @@ -91,31 +92,55 @@ acpi_status acpi_ex_enter_interpreter(void) status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex")); + ACPI_ERROR((AE_INFO, + "Could not acquire AML Interpreter mutex")); } - return_ACPI_STATUS(status); + return_VOID; } /******************************************************************************* * - * FUNCTION: acpi_ex_exit_interpreter + * FUNCTION: acpi_ex_reacquire_interpreter * * PARAMETERS: None * * RETURN: None * - * DESCRIPTION: Exit the interpreter execution region + * DESCRIPTION: Reacquire the interpreter execution region from within the + * interpreter code. Failure to enter the interpreter region is a + * fatal system error. Used in conjuction with + * relinquish_interpreter + * + ******************************************************************************/ + +void acpi_ex_reacquire_interpreter(void) +{ + ACPI_FUNCTION_TRACE(ex_reacquire_interpreter); + + /* + * If the global serialized flag is set, do not release the interpreter, + * since it was not actually released by acpi_ex_relinquish_interpreter. + * This forces the interpreter to be single threaded. + */ + if (!acpi_gbl_all_methods_serialized) { + acpi_ex_enter_interpreter(); + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_exit_interpreter + * + * PARAMETERS: None + * + * RETURN: None * - * Cases where the interpreter is unlocked: - * 1) Completion of the execution of a control method - * 2) Method blocked on a Sleep() AML opcode - * 3) Method blocked on an Acquire() AML opcode - * 4) Method blocked on a Wait() AML opcode - * 5) Method blocked to acquire the global lock - * 6) Method blocked to execute a serialized control method that is - * already executing - * 7) About to invoke a user-installed opregion handler + * DESCRIPTION: Exit the interpreter execution region. This is the top level + * routine used to exit the interpreter when all processing has + * been completed. * ******************************************************************************/ @@ -127,7 +152,46 @@ void acpi_ex_exit_interpreter(void) status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not release interpreter mutex")); + ACPI_ERROR((AE_INFO, + "Could not release AML Interpreter mutex")); + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_relinquish_interpreter + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Exit the interpreter execution region, from within the + * interpreter - before attempting an operation that will possibly + * block the running thread. + * + * Cases where the interpreter is unlocked internally + * 1) Method to be blocked on a Sleep() AML opcode + * 2) Method to be blocked on an Acquire() AML opcode + * 3) Method to be blocked on a Wait() AML opcode + * 4) Method to be blocked to acquire the global lock + * 5) Method to be blocked waiting to execute a serialized control method + * that is currently executing + * 6) About to invoke a user-installed opregion handler + * + ******************************************************************************/ + +void acpi_ex_relinquish_interpreter(void) +{ + ACPI_FUNCTION_TRACE(ex_relinquish_interpreter); + + /* + * If the global serialized flag is set, do not release the interpreter. + * This forces the interpreter to be single threaded. + */ + if (!acpi_gbl_all_methods_serialized) { + acpi_ex_exit_interpreter(); } return_VOID; @@ -141,8 +205,8 @@ void acpi_ex_exit_interpreter(void) * * RETURN: none * - * DESCRIPTION: Truncate a number to 32-bits if the currently executing method - * belongs to a 32-bit ACPI table. + * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is + * 32-bit, as determined by the revision of the DSDT. * ******************************************************************************/ diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index c84b1faba28c..76c525dc590b 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -152,7 +152,6 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) ACPI_EXPORT_SYMBOL(acpi_get_firmware_waking_vector) #endif - /******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_prep diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index 26fd0dd6953d..97b2ac57c16b 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -75,7 +75,7 @@ ACPI_MODULE_NAME("nseval") * MUTEX: Locks interpreter * ******************************************************************************/ -acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) +acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) { acpi_status status; @@ -154,11 +154,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) * Execute the method via the interpreter. The interpreter is locked * here before calling into the AML parser */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - + acpi_ex_enter_interpreter(); status = acpi_ps_execute_method(info); acpi_ex_exit_interpreter(); } else { @@ -182,10 +178,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) * resolution, we must lock it because we could access an opregion. * The opregion access code assumes that the interpreter is locked. */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + acpi_ex_enter_interpreter(); /* Function has a strange interface */ diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index c4ab615f77fe..33db2241044e 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -214,7 +214,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle, u32 level, void *context, void **return_value) { acpi_object_type type; - acpi_status status; + acpi_status status = AE_OK; struct acpi_init_walk_info *info = (struct acpi_init_walk_info *)context; struct acpi_namespace_node *node = @@ -268,10 +268,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle, /* * Must lock the interpreter before executing AML code */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return (status); - } + acpi_ex_enter_interpreter(); /* * Each of these types can contain executable AML code within the diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c index 94eb8f332d94..280b8357c46c 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/namespace/nswalk.c @@ -65,10 +65,8 @@ ACPI_MODULE_NAME("nswalk") * within Scope is returned. * ******************************************************************************/ -struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, - struct acpi_namespace_node - *parent_node, - struct acpi_namespace_node +struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node + *parent_node, struct acpi_namespace_node *child_node) { struct acpi_namespace_node *next_node = NULL; diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index 8904d0fae6a2..be4f2899de74 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -48,7 +48,6 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfeval") - #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -73,8 +72,8 @@ ACPI_MODULE_NAME("nsxfeval") acpi_status acpi_evaluate_object_typed(acpi_handle handle, acpi_string pathname, - struct acpi_object_list * external_params, - struct acpi_buffer * return_buffer, + struct acpi_object_list *external_params, + struct acpi_buffer *return_buffer, acpi_object_type return_type) { acpi_status status; @@ -143,7 +142,6 @@ acpi_evaluate_object_typed(acpi_handle handle, ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed) #endif /* ACPI_FUTURE_USAGE */ - /******************************************************************************* * * FUNCTION: acpi_evaluate_object @@ -170,7 +168,6 @@ acpi_evaluate_object(acpi_handle handle, struct acpi_buffer *return_buffer) { acpi_status status; - acpi_status status2; struct acpi_evaluate_info *info; acpi_size buffer_space_needed; u32 i; @@ -329,14 +326,12 @@ acpi_evaluate_object(acpi_handle handle, * Delete the internal return object. NOTE: Interpreter must be * locked to avoid race condition. */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_SUCCESS(status2)) { + acpi_ex_enter_interpreter(); - /* Remove one reference on the return object (should delete it) */ + /* Remove one reference on the return object (should delete it) */ - acpi_ut_remove_reference(info->return_object); - acpi_ex_exit_interpreter(); - } + acpi_ut_remove_reference(info->return_object); + acpi_ex_exit_interpreter(); } cleanup: diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c2bed56915e1..b998340e23d4 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -71,6 +71,7 @@ static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; +static struct workqueue_struct *kacpi_notify_wq; static void __init acpi_request_region (struct acpi_generic_address *addr, unsigned int length, char *desc) @@ -137,8 +138,9 @@ acpi_status acpi_os_initialize1(void) return AE_NULL_ENTRY; } kacpid_wq = create_singlethread_workqueue("kacpid"); + kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify"); BUG_ON(!kacpid_wq); - + BUG_ON(!kacpi_notify_wq); return AE_OK; } @@ -150,6 +152,7 @@ acpi_status acpi_os_terminate(void) } destroy_workqueue(kacpid_wq); + destroy_workqueue(kacpi_notify_wq); return AE_OK; } @@ -603,6 +606,23 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ static void acpi_os_execute_deferred(struct work_struct *work) { struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); + if (!dpc) { + printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); + return; + } + + dpc->function(dpc->context); + kfree(dpc); + + /* Yield cpu to notify thread */ + cond_resched(); + + return; +} + +static void acpi_os_execute_notify(struct work_struct *work) +{ + struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); if (!dpc) { printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); @@ -637,14 +657,12 @@ acpi_status acpi_os_execute(acpi_execute_type type, acpi_status status = AE_OK; struct acpi_os_dpc *dpc; - ACPI_FUNCTION_TRACE("os_queue_for_execution"); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); if (!function) - return_ACPI_STATUS(AE_BAD_PARAMETER); + return AE_BAD_PARAMETER; /* * Allocate/initialize DPC structure. Note that this memory will be @@ -662,14 +680,21 @@ acpi_status acpi_os_execute(acpi_execute_type type, dpc->function = function; dpc->context = context; - INIT_WORK(&dpc->work, acpi_os_execute_deferred); - if (!queue_work(kacpid_wq, &dpc->work)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + if (type == OSL_NOTIFY_HANDLER) { + INIT_WORK(&dpc->work, acpi_os_execute_notify); + if (!queue_work(kacpi_notify_wq, &dpc->work)) { + status = AE_ERROR; + kfree(dpc); + } + } else { + INIT_WORK(&dpc->work, acpi_os_execute_deferred); + if (!queue_work(kacpid_wq, &dpc->work)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Call to queue_work() failed.\n")); - kfree(dpc); - status = AE_ERROR; + status = AE_ERROR; + kfree(dpc); + } } - return_ACPI_STATUS(status); } diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 16d8b6cc3c22..9296e86761d7 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -185,459 +185,453 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* Index Name Parser Args Interpreter Args ObjectType Class Type Flags */ /* 00 */ ACPI_OP("Zero", ARGP_ZERO_OP, ARGI_ZERO_OP, ACPI_TYPE_INTEGER, - AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), + AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), /* 01 */ ACPI_OP("One", ARGP_ONE_OP, ARGI_ONE_OP, ACPI_TYPE_INTEGER, - AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), + AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), /* 02 */ ACPI_OP("Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP, - ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_SIMPLE, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 03 */ ACPI_OP("Name", ARGP_NAME_OP, ARGI_NAME_OP, ACPI_TYPE_ANY, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 04 */ ACPI_OP("ByteConst", ARGP_BYTE_OP, ARGI_BYTE_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 05 */ ACPI_OP("WordConst", ARGP_WORD_OP, ARGI_WORD_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 06 */ ACPI_OP("DwordConst", ARGP_DWORD_OP, ARGI_DWORD_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 07 */ ACPI_OP("String", ARGP_STRING_OP, ARGI_STRING_OP, - ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 08 */ ACPI_OP("Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP, - ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_NO_OBJ, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_NO_OBJ, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 09 */ ACPI_OP("Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP, - ACPI_TYPE_BUFFER, AML_CLASS_CREATE, - AML_TYPE_CREATE_OBJECT, - AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), + ACPI_TYPE_BUFFER, AML_CLASS_CREATE, + AML_TYPE_CREATE_OBJECT, + AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), /* 0A */ ACPI_OP("Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP, - ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, - AML_TYPE_CREATE_OBJECT, - AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), + ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, + AML_TYPE_CREATE_OBJECT, + AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), /* 0B */ ACPI_OP("Method", ARGP_METHOD_OP, ARGI_METHOD_OP, - ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_COMPLEX, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED | AML_DEFER), + ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_COMPLEX, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED | AML_DEFER), /* 0C */ ACPI_OP("Local0", ARGP_LOCAL0, ARGI_LOCAL0, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 0D */ ACPI_OP("Local1", ARGP_LOCAL1, ARGI_LOCAL1, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 0E */ ACPI_OP("Local2", ARGP_LOCAL2, ARGI_LOCAL2, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 0F */ ACPI_OP("Local3", ARGP_LOCAL3, ARGI_LOCAL3, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 10 */ ACPI_OP("Local4", ARGP_LOCAL4, ARGI_LOCAL4, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 11 */ ACPI_OP("Local5", ARGP_LOCAL5, ARGI_LOCAL5, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 12 */ ACPI_OP("Local6", ARGP_LOCAL6, ARGI_LOCAL6, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 13 */ ACPI_OP("Local7", ARGP_LOCAL7, ARGI_LOCAL7, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 14 */ ACPI_OP("Arg0", ARGP_ARG0, ARGI_ARG0, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 15 */ ACPI_OP("Arg1", ARGP_ARG1, ARGI_ARG1, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 16 */ ACPI_OP("Arg2", ARGP_ARG2, ARGI_ARG2, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 17 */ ACPI_OP("Arg3", ARGP_ARG3, ARGI_ARG3, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 18 */ ACPI_OP("Arg4", ARGP_ARG4, ARGI_ARG4, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 19 */ ACPI_OP("Arg5", ARGP_ARG5, ARGI_ARG5, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 1A */ ACPI_OP("Arg6", ARGP_ARG6, ARGI_ARG6, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 1B */ ACPI_OP("Store", ARGP_STORE_OP, ARGI_STORE_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R), /* 1C */ ACPI_OP("RefOf", ARGP_REF_OF_OP, ARGI_REF_OF_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R), /* 1D */ ACPI_OP("Add", ARGP_ADD_OP, ARGI_ADD_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 1E */ ACPI_OP("Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), /* 1F */ ACPI_OP("Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 20 */ ACPI_OP("Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), /* 21 */ ACPI_OP("Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), /* 22 */ ACPI_OP("Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 23 */ ACPI_OP("Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_2T_1R, - AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_2T_1R, + AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT), /* 24 */ ACPI_OP("ShiftLeft", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 25 */ ACPI_OP("ShiftRight", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 26 */ ACPI_OP("And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 27 */ ACPI_OP("NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 28 */ ACPI_OP("Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 29 */ ACPI_OP("NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 2A */ ACPI_OP("XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 2B */ ACPI_OP("Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 2C */ ACPI_OP("FindSetLeftBit", ARGP_FIND_SET_LEFT_BIT_OP, - ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 2D */ ACPI_OP("FindSetRightBit", ARGP_FIND_SET_RIGHT_BIT_OP, - ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 2E */ ACPI_OP("DerefOf", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), /* 2F */ ACPI_OP("Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R), /* 30 */ ACPI_OP("SizeOf", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), /* 31 */ ACPI_OP("Index", ARGP_INDEX_OP, ARGI_INDEX_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R), /* 32 */ ACPI_OP("Match", ARGP_MATCH_OP, ARGI_MATCH_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, - AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, + AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT), /* 33 */ ACPI_OP("CreateDWordField", ARGP_CREATE_DWORD_FIELD_OP, - ARGI_CREATE_DWORD_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_DWORD_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 34 */ ACPI_OP("CreateWordField", ARGP_CREATE_WORD_FIELD_OP, - ARGI_CREATE_WORD_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_WORD_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 35 */ ACPI_OP("CreateByteField", ARGP_CREATE_BYTE_FIELD_OP, - ARGI_CREATE_BYTE_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_BYTE_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 36 */ ACPI_OP("CreateBitField", ARGP_CREATE_BIT_FIELD_OP, - ARGI_CREATE_BIT_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_BIT_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 37 */ ACPI_OP("ObjectType", ARGP_TYPE_OP, ARGI_TYPE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), /* 38 */ ACPI_OP("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | - AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT), /* 39 */ ACPI_OP("LOr", ARGP_LOR_OP, ARGI_LOR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | - AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT), /* 3A */ ACPI_OP("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), /* 3B */ ACPI_OP("LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), /* 3C */ ACPI_OP("LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), /* 3D */ ACPI_OP("LLess", ARGP_LLESS_OP, ARGI_LLESS_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), /* 3E */ ACPI_OP("If", ARGP_IF_OP, ARGI_IF_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), /* 3F */ ACPI_OP("Else", ARGP_ELSE_OP, ARGI_ELSE_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), /* 40 */ ACPI_OP("While", ARGP_WHILE_OP, ARGI_WHILE_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), /* 41 */ ACPI_OP("Noop", ARGP_NOOP_OP, ARGI_NOOP_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), /* 42 */ ACPI_OP("Return", ARGP_RETURN_OP, ARGI_RETURN_OP, - ACPI_TYPE_ANY, AML_CLASS_CONTROL, - AML_TYPE_CONTROL, AML_HAS_ARGS), + ACPI_TYPE_ANY, AML_CLASS_CONTROL, + AML_TYPE_CONTROL, AML_HAS_ARGS), /* 43 */ ACPI_OP("Break", ARGP_BREAK_OP, ARGI_BREAK_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), /* 44 */ ACPI_OP("BreakPoint", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP, - ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), + ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), /* 45 */ ACPI_OP("Ones", ARGP_ONES_OP, ARGI_ONES_OP, ACPI_TYPE_INTEGER, - AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), + AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), /* Prefixed opcodes (Two-byte opcodes with a prefix op) */ /* 46 */ ACPI_OP("Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP, ACPI_TYPE_MUTEX, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 47 */ ACPI_OP("Event", ARGP_EVENT_OP, ARGI_EVENT_OP, ACPI_TYPE_EVENT, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, - AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, + AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), /* 48 */ ACPI_OP("CondRefOf", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), /* 49 */ ACPI_OP("CreateField", ARGP_CREATE_FIELD_OP, - ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, - AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_FIELD | AML_CREATE), + ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, + AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_FIELD | AML_CREATE), /* 4A */ ACPI_OP("Load", ARGP_LOAD_OP, ARGI_LOAD_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R, - AML_FLAGS_EXEC_1A_1T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R, + AML_FLAGS_EXEC_1A_1T_0R), /* 4B */ ACPI_OP("Stall", ARGP_STALL_OP, ARGI_STALL_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, - AML_FLAGS_EXEC_1A_0T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, + AML_FLAGS_EXEC_1A_0T_0R), /* 4C */ ACPI_OP("Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, - AML_FLAGS_EXEC_1A_0T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, + AML_FLAGS_EXEC_1A_0T_0R), /* 4D */ ACPI_OP("Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), /* 4E */ ACPI_OP("Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), /* 4F */ ACPI_OP("Wait", ARGP_WAIT_OP, ARGI_WAIT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R), /* 50 */ ACPI_OP("Reset", ARGP_RESET_OP, ARGI_RESET_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, - AML_FLAGS_EXEC_1A_0T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, + AML_FLAGS_EXEC_1A_0T_0R), /* 51 */ ACPI_OP("Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), /* 52 */ ACPI_OP("FromBCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 53 */ ACPI_OP("ToBCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 54 */ ACPI_OP("Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), /* 55 */ ACPI_OP("Revision", ARGP_REVISION_OP, ARGI_REVISION_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_CONSTANT, 0), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_CONSTANT, 0), /* 56 */ ACPI_OP("Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_CONSTANT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_CONSTANT, 0), /* 57 */ ACPI_OP("Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R, - AML_FLAGS_EXEC_3A_0T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R, + AML_FLAGS_EXEC_3A_0T_0R), /* 58 */ ACPI_OP("OperationRegion", ARGP_REGION_OP, ARGI_REGION_OP, - ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_COMPLEX, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED | AML_DEFER), + ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_COMPLEX, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED | AML_DEFER), /* 59 */ ACPI_OP("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, ACPI_TYPE_ANY, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_FIELD), + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), /* 5A */ ACPI_OP("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP, - ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_NO_OBJ, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_NO_OBJ, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 5B */ ACPI_OP("Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP, - ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_SIMPLE, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 5C */ ACPI_OP("PowerResource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP, - ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_SIMPLE, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 5D */ ACPI_OP("ThermalZone", ARGP_THERMAL_ZONE_OP, - ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL, + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 5E */ ACPI_OP("IndexField", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP, - ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_FIELD), + ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), /* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP, - ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_FIELD), + ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), /* Internal opcodes that map to invalid AML opcodes */ /* 60 */ ACPI_OP("LNotEqual", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP, - ACPI_TYPE_ANY, AML_CLASS_INTERNAL, - AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_INTERNAL, + AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), /* 61 */ ACPI_OP("LLessEqual", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP, - ACPI_TYPE_ANY, AML_CLASS_INTERNAL, - AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_INTERNAL, + AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), /* 62 */ ACPI_OP("LGreaterEqual", ARGP_LGREATEREQUAL_OP, - ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY, - AML_CLASS_INTERNAL, AML_TYPE_BOGUS, - AML_HAS_ARGS | AML_CONSTANT), + ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, + AML_HAS_ARGS | AML_CONSTANT), /* 63 */ ACPI_OP("-NamePath-", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE), /* 64 */ ACPI_OP("-MethodCall-", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP, - ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL, - AML_TYPE_METHOD_CALL, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE), + ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL, + AML_TYPE_METHOD_CALL, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE), /* 65 */ ACPI_OP("-ByteList-", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP, - ACPI_TYPE_ANY, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, 0), + ACPI_TYPE_ANY, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, 0), /* 66 */ ACPI_OP("-ReservedField-", ARGP_RESERVEDFIELD_OP, - ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY, - AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), + ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), /* 67 */ ACPI_OP("-NamedField-", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP, - ACPI_TYPE_ANY, AML_CLASS_INTERNAL, - AML_TYPE_BOGUS, - AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), + ACPI_TYPE_ANY, AML_CLASS_INTERNAL, + AML_TYPE_BOGUS, + AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), /* 68 */ ACPI_OP("-AccessField-", ARGP_ACCESSFIELD_OP, - ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY, - AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), + ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), /* 69 */ ACPI_OP("-StaticString", ARGP_STATICSTRING_OP, - ARGI_STATICSTRING_OP, ACPI_TYPE_ANY, - AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), + ARGI_STATICSTRING_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), /* 6A */ ACPI_OP("-Return Value-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, - AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN, - AML_HAS_ARGS | AML_HAS_RETVAL), + AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN, + AML_HAS_ARGS | AML_HAS_RETVAL), /* 6B */ ACPI_OP("-UNKNOWN_OP-", ARG_NONE, ARG_NONE, ACPI_TYPE_INVALID, - AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS), + AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS), /* 6C */ ACPI_OP("-ASCII_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, - AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS), + AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS), /* 6D */ ACPI_OP("-PREFIX_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, - AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS), + AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS), /* ACPI 2.0 opcodes */ /* 6E */ ACPI_OP("QwordConst", ARGP_QWORD_OP, ARGI_QWORD_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 6F */ ACPI_OP("Package", /* Var */ ARGP_VAR_PACKAGE_OP, ARGI_VAR_PACKAGE_OP, ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER), /* 70 */ ACPI_OP("ConcatenateResTemplate", ARGP_CONCAT_RES_OP, - ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), + ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), /* 71 */ ACPI_OP("Mod", ARGP_MOD_OP, ARGI_MOD_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), /* 72 */ ACPI_OP("CreateQWordField", ARGP_CREATE_QWORD_FIELD_OP, - ARGI_CREATE_QWORD_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_QWORD_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 73 */ ACPI_OP("ToBuffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 74 */ ACPI_OP("ToDecimalString", ARGP_TO_DEC_STR_OP, - ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 75 */ ACPI_OP("ToHexString", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 76 */ ACPI_OP("ToInteger", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 77 */ ACPI_OP("ToString", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), /* 78 */ ACPI_OP("CopyObject", ARGP_COPY_OP, ARGI_COPY_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), /* 79 */ ACPI_OP("Mid", ARGP_MID_OP, ARGI_MID_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R, - AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R, + AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT), /* 7A */ ACPI_OP("Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP, - ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), + ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), /* 7B */ ACPI_OP("LoadTable", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), /* 7C */ ACPI_OP("DataTableRegion", ARGP_DATA_REGION_OP, - ARGI_DATA_REGION_OP, ACPI_TYPE_REGION, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ARGI_DATA_REGION_OP, ACPI_TYPE_REGION, + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP, - ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_NO_OBJ, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE), + ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_NO_OBJ, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE), /* ACPI 3.0 opcodes */ /* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, - AML_FLAGS_EXEC_0A_0T_1R) + AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, + AML_FLAGS_EXEC_0A_0T_1R) /*! [End] no source code translation !*/ }; diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index 8c6d3fdec38a..0dd2ce8a3475 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -567,7 +567,8 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, (*sub_object_list)->string. length + 1); } else { - temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node); + temp_size_needed += + acpi_ns_get_pathname_length((*sub_object_list)->reference.node); } } else { /* diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index cc48ab05676c..50da494c3ee2 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -267,16 +267,19 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, * If BIOS erroneously reversed the _PRT source_name and source_index, * then reverse them back. */ - if (ACPI_GET_OBJECT_TYPE (sub_object_list[3]) != ACPI_TYPE_INTEGER) { + if (ACPI_GET_OBJECT_TYPE(sub_object_list[3]) != + ACPI_TYPE_INTEGER) { if (acpi_gbl_enable_interpreter_slack) { source_name_index = 3; source_index_index = 2; - printk(KERN_WARNING "ACPI: Handling Garbled _PRT entry\n"); + printk(KERN_WARNING + "ACPI: Handling Garbled _PRT entry\n"); } else { ACPI_ERROR((AE_INFO, - "(PRT[%X].source_index) Need Integer, found %s", - index, - acpi_ut_get_object_type_name(sub_object_list[3]))); + "(PRT[%X].source_index) Need Integer, found %s", + index, + acpi_ut_get_object_type_name + (sub_object_list[3]))); return_ACPI_STATUS(AE_BAD_DATA); } } diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c index de20a5d6decf..46da116a4030 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/resources/rsdump.c @@ -46,7 +46,6 @@ #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsdump") - #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) /* Local prototypes */ static void acpi_rs_out_string(char *title, char *value); @@ -489,10 +488,9 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) /* * Optional resource_source for Address resources */ - acpi_rs_dump_resource_source(ACPI_CAST_PTR - (struct - acpi_resource_source, - target)); + acpi_rs_dump_resource_source(ACPI_CAST_PTR(struct + acpi_resource_source, + target)); break; default: diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c index 7e3c335ab320..2c2adb6292c1 100644 --- a/drivers/acpi/resources/rsinfo.c +++ b/drivers/acpi/resources/rsinfo.c @@ -142,7 +142,7 @@ struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = { }; #endif -#endif /* ACPI_FUTURE_USAGE */ +#endif /* ACPI_FUTURE_USAGE */ /* * Base sizes for external AML resource descriptors, indexed by internal type. * Includes size of the descriptor header (1 byte for small descriptors, diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index a92755c8877d..ca21e4660c79 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -153,10 +153,9 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, /* Perform the conversion */ - status = acpi_rs_convert_resource_to_aml(resource, - ACPI_CAST_PTR(union - aml_resource, - aml), + status = acpi_rs_convert_resource_to_aml(resource, ACPI_CAST_PTR(union + aml_resource, + aml), acpi_gbl_set_resource_dispatch [resource->type]); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index 3b63b561b94e..c7081afa893a 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -46,7 +46,6 @@ #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsmisc") - #define INIT_RESOURCE_TYPE(i) i->resource_offset #define INIT_RESOURCE_LENGTH(i) i->aml_offset #define INIT_TABLE_LENGTH(i) i->value @@ -429,8 +428,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, * Optional resource_source (Index and String) */ aml_length = - acpi_rs_set_resource_source(aml, - (acpi_rs_length) + acpi_rs_set_resource_source(aml, (acpi_rs_length) aml_length, source); acpi_rs_set_resource_length(aml_length, aml); break; diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index 2442a8f8df57..11c0bd7b9cfd 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -353,10 +353,8 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, * * Zero the entire area of the buffer. */ - total_length = - (u32) - ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + - 1; + total_length = (u32) + ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1; total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); ACPI_MEMSET(resource_source->string_ptr, 0, total_length); diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 991f8901498c..f63813a358c5 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -217,7 +217,6 @@ acpi_get_current_resources(acpi_handle device_handle, } ACPI_EXPORT_SYMBOL(acpi_get_current_resources) - #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -261,7 +260,6 @@ acpi_get_possible_resources(acpi_handle device_handle, ACPI_EXPORT_SYMBOL(acpi_get_possible_resources) #endif /* ACPI_FUTURE_USAGE */ - /******************************************************************************* * * FUNCTION: acpi_set_current_resources @@ -496,7 +494,6 @@ ACPI_EXPORT_SYMBOL(acpi_rs_match_vendor_resource) * each resource in the list. * ******************************************************************************/ - acpi_status acpi_walk_resources(acpi_handle device_handle, char *name, diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 52b23471dd69..bc7e16ec8393 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -222,7 +222,7 @@ static struct hibernation_ops acpi_hibernation_ops = { .enter = acpi_hibernation_enter, .finish = acpi_hibernation_finish, }; -#endif /* CONFIG_SOFTWARE_SUSPEND */ +#endif /* CONFIG_SOFTWARE_SUSPEND */ /* * Toshiba fails to preserve interrupts over S1, reinitialization @@ -276,4 +276,3 @@ int __init acpi_sleep_init(void) return 0; } - diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 76b45f0b8341..61f1822cc350 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -349,8 +349,7 @@ acpi_system_write_alarm(struct file *file, end: return_VALUE(result ? result : count); } -#endif /* HAVE_ACPI_LEGACY_ALARM */ - +#endif /* HAVE_ACPI_LEGACY_ALARM */ extern struct list_head acpi_wakeup_device_list; extern spinlock_t acpi_device_lock; @@ -380,8 +379,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) dev->wakeup.state.enabled ? "enabled" : "disabled"); if (ldev) seq_printf(seq, "%s:%s", - ldev->bus ? ldev->bus->name : "no-bus", - ldev->bus_id); + ldev->bus ? ldev->bus->name : "no-bus", + ldev->bus_id); seq_printf(seq, "\n"); put_device(ldev); @@ -490,7 +489,7 @@ static u32 rtc_handler(void *context) return ACPI_INTERRUPT_HANDLED; } -#endif /* HAVE_ACPI_LEGACY_ALARM */ +#endif /* HAVE_ACPI_LEGACY_ALARM */ static int __init acpi_sleep_proc_init(void) { @@ -517,7 +516,7 @@ static int __init acpi_sleep_proc_init(void) entry->proc_fops = &acpi_system_alarm_fops; acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); -#endif /* HAVE_ACPI_LEGACY_ALARM */ +#endif /* HAVE_ACPI_LEGACY_ALARM */ /* 'wakeup device' [R/W] */ entry = diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c index 1db833eb2417..1285e91474fb 100644 --- a/drivers/acpi/tables/tbfadt.c +++ b/drivers/acpi/tables/tbfadt.c @@ -334,7 +334,8 @@ static void acpi_tb_convert_fadt(void) (acpi_gbl_FADT.xpm1a_event_block.address + pm1_register_length)); /* Don't forget to copy space_id of the GAS */ - acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id; + acpi_gbl_xpm1a_enable.space_id = + acpi_gbl_FADT.xpm1a_event_block.space_id; /* The PM1B register block is optional, ignore if not present */ @@ -344,7 +345,8 @@ static void acpi_tb_convert_fadt(void) (acpi_gbl_FADT.xpm1b_event_block. address + pm1_register_length)); /* Don't forget to copy space_id of the GAS */ - acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id; + acpi_gbl_xpm1b_enable.space_id = + acpi_gbl_FADT.xpm1a_event_block.space_id; } diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 417ef5fa7666..5b302c4e293f 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -201,6 +201,7 @@ acpi_status acpi_reallocate_root_table(void) return_ACPI_STATUS(AE_OK); } + /******************************************************************************* * * FUNCTION: acpi_load_table @@ -262,7 +263,7 @@ ACPI_EXPORT_SYMBOL(acpi_load_table) acpi_status acpi_get_table_header(char *signature, acpi_native_uint instance, - struct acpi_table_header *out_table_header) + struct acpi_table_header * out_table_header) { acpi_native_uint i; acpi_native_uint j; @@ -321,7 +322,6 @@ acpi_get_table_header(char *signature, ACPI_EXPORT_SYMBOL(acpi_get_table_header) - /****************************************************************************** * * FUNCTION: acpi_unload_table_id @@ -346,11 +346,11 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) continue; } /* - * Delete all namespace objects owned by this table. Note that these - * objects can appear anywhere in the namespace by virtue of the AML - * "Scope" operator. Thus, we need to track ownership by an ID, not - * simply a position within the hierarchy - */ + * Delete all namespace objects owned by this table. Note that these + * objects can appear anywhere in the namespace by virtue of the AML + * "Scope" operator. Thus, we need to track ownership by an ID, not + * simply a position within the hierarchy + */ acpi_tb_delete_namespace_by_owner(i); status = acpi_tb_release_owner_id(i); acpi_tb_set_table_loaded_flag(i, FALSE); @@ -376,7 +376,7 @@ ACPI_EXPORT_SYMBOL(acpi_unload_table_id) *****************************************************************************/ acpi_status acpi_get_table(char *signature, - acpi_native_uint instance, struct acpi_table_header ** out_table) + acpi_native_uint instance, struct acpi_table_header **out_table) { acpi_native_uint i; acpi_native_uint j; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 589b98b7b216..1ada017d01ef 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -59,8 +59,6 @@ #define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0 #define ACPI_THERMAL_NOTIFY_HOT 0xF1 #define ACPI_THERMAL_MODE_ACTIVE 0x00 -#define ACPI_THERMAL_MODE_PASSIVE 0x01 -#define ACPI_THERMAL_MODE_CRITICAL 0xff #define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" #define ACPI_THERMAL_MAX_ACTIVE 10 @@ -86,9 +84,6 @@ static int acpi_thermal_resume(struct acpi_device *device); static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file); -static ssize_t acpi_thermal_write_trip_points(struct file *, - const char __user *, size_t, - loff_t *); static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file); static ssize_t acpi_thermal_write_cooling_mode(struct file *, const char __user *, size_t, @@ -167,7 +162,6 @@ struct acpi_thermal { unsigned long temperature; unsigned long last_temperature; unsigned long polling_frequency; - u8 cooling_mode; volatile u8 zombie; struct acpi_thermal_flags flags; struct acpi_thermal_state state; @@ -193,7 +187,6 @@ static const struct file_operations acpi_thermal_temp_fops = { static const struct file_operations acpi_thermal_trip_fops = { .open = acpi_thermal_trip_open_fs, .read = seq_read, - .write = acpi_thermal_write_trip_points, .llseek = seq_lseek, .release = single_release, }; @@ -297,11 +290,6 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode) if (ACPI_FAILURE(status)) return -ENODEV; - tz->cooling_mode = mode; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n", - mode ? "passive" : "active")); - return 0; } @@ -889,67 +877,6 @@ static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data); } -static ssize_t -acpi_thermal_write_trip_points(struct file *file, - const char __user * buffer, - size_t count, loff_t * ppos) -{ - struct seq_file *m = file->private_data; - struct acpi_thermal *tz = m->private; - - char *limit_string; - int num, critical, hot, passive; - int *active; - int i = 0; - - - limit_string = kzalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL); - if (!limit_string) - return -ENOMEM; - - active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL); - if (!active) { - kfree(limit_string); - return -ENOMEM; - } - - if (!tz || (count > ACPI_THERMAL_MAX_LIMIT_STR_LEN - 1)) { - count = -EINVAL; - goto end; - } - - if (copy_from_user(limit_string, buffer, count)) { - count = -EFAULT; - goto end; - } - - limit_string[count] = '\0'; - - num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", - &critical, &hot, &passive, - &active[0], &active[1], &active[2], &active[3], &active[4], - &active[5], &active[6], &active[7], &active[8], - &active[9]); - if (!(num >= 5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) { - count = -EINVAL; - goto end; - } - - tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical); - tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot); - tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive); - for (i = 0; i < num - 3; i++) { - if (!(tz->trips.active[i].flags.valid)) - break; - tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]); - } - - end: - kfree(active); - kfree(limit_string); - return count; -} - static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset) { struct acpi_thermal *tz = seq->private; @@ -958,15 +885,10 @@ static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset) if (!tz) goto end; - if (!tz->flags.cooling_mode) { + if (!tz->flags.cooling_mode) seq_puts(seq, "<setting not supported>\n"); - } - - if (tz->cooling_mode == ACPI_THERMAL_MODE_CRITICAL) - seq_printf(seq, "cooling mode: critical\n"); else - seq_printf(seq, "cooling mode: %s\n", - tz->cooling_mode ? "passive" : "active"); + seq_puts(seq, "0 - Active; 1 - Passive\n"); end: return 0; @@ -1223,28 +1145,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE); if (!result) tz->flags.cooling_mode = 1; - else { - /* Oh,we have not _SCP method. - Generally show cooling_mode by _ACx, _PSV,spec 12.2 */ - tz->flags.cooling_mode = 0; - if (tz->trips.active[0].flags.valid - && tz->trips.passive.flags.valid) { - if (tz->trips.passive.temperature > - tz->trips.active[0].temperature) - tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE; - else - tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE; - } else if (!tz->trips.active[0].flags.valid - && tz->trips.passive.flags.valid) { - tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE; - } else if (tz->trips.active[0].flags.valid - && !tz->trips.passive.flags.valid) { - tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE; - } else { - /* _ACx and _PSV are optional, but _CRT is required */ - tz->cooling_mode = ACPI_THERMAL_MODE_CRITICAL; - } - } /* Get default polling frequency [_TZP] (optional) */ if (tzp) diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 55a764807499..6e56d5f7c43a 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -107,7 +107,6 @@ acpi_status acpi_ut_create_caches(void) if (ACPI_FAILURE(status)) { return (status); } - #ifdef ACPI_DBG_TRACK_ALLOCATIONS /* Memory allocation lists */ diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c index 870f6edeb5f2..285a0f531760 100644 --- a/drivers/acpi/utilities/utcache.c +++ b/drivers/acpi/utilities/utcache.c @@ -45,7 +45,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utcache") - #ifdef ACPI_USE_LOCAL_CACHE /******************************************************************************* * @@ -64,7 +63,7 @@ ACPI_MODULE_NAME("utcache") acpi_status acpi_os_create_cache(char *cache_name, u16 object_size, - u16 max_depth, struct acpi_memory_list **return_cache) + u16 max_depth, struct acpi_memory_list ** return_cache) { struct acpi_memory_list *cache; diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index 84d529db0a66..4c1e00874dff 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -814,7 +814,9 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type, /* * Create the object array */ - target_object->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) source_object->package.count + 1) * sizeof(void *)); + target_object->package.elements = + ACPI_ALLOCATE_ZEROED(((acpi_size) source_object->package. + count + 1) * sizeof(void *)); if (!target_object->package.elements) { status = AE_NO_MEMORY; goto error_exit; diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 61ad4f2daee2..c7e128e5369b 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -45,7 +45,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdebug") - #ifdef ACPI_DEBUG_OUTPUT static acpi_thread_id acpi_gbl_prev_thread_id; static char *acpi_gbl_fn_entry_str = "----Entry"; @@ -181,7 +180,8 @@ acpi_ut_debug_print(u32 requested_debug_level, if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf ("\n**** Context Switch from TID %lX to TID %lX ****\n\n", - (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id); + (unsigned long)acpi_gbl_prev_thread_id, + (unsigned long)thread_id); } acpi_gbl_prev_thread_id = thread_id; diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 673a0caa4073..f777cebdc46d 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -170,6 +170,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) acpi_os_delete_mutex(object->mutex.os_mutex); acpi_gbl_global_lock_mutex = NULL; } else { + acpi_ex_unlink_mutex(object); acpi_os_delete_mutex(object->mutex.os_mutex); } break; diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index af33358a964b..1621655d6e2b 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -55,12 +55,10 @@ ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) * Static global variable initialization. * ******************************************************************************/ - /* * We want the debug switches statically initialized so they * are already set when the debugger is entered. */ - /* Debug switch - level and trace mask */ u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT; @@ -735,5 +733,5 @@ void acpi_ut_init_globals(void) } ACPI_EXPORT_SYMBOL(acpi_dbg_level) -ACPI_EXPORT_SYMBOL(acpi_dbg_layer) -ACPI_EXPORT_SYMBOL(acpi_gpe_count) + ACPI_EXPORT_SYMBOL(acpi_dbg_layer) + ACPI_EXPORT_SYMBOL(acpi_gpe_count) diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 50133fffe420..2d19f71e9cfa 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -802,9 +802,8 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) valid_digits++; - if (sign_of0x - && ((valid_digits > 16) - || ((valid_digits > 8) && mode32))) { + if (sign_of0x && ((valid_digits > 16) + || ((valid_digits > 8) && mode32))) { /* * This is to_integer operation case. * No any restrictions for string-to-integer conversion, @@ -1049,6 +1048,7 @@ acpi_ut_exception(char *module_name, acpi_os_vprintf(format, args); acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); } + EXPORT_SYMBOL(acpi_ut_exception); void ACPI_INTERNAL_VAR_XFACE diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index cbad2ef5987d..4820bc86d1f5 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -244,7 +244,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %lX attempting to acquire Mutex [%s]\n", - (unsigned long) this_thread_id, + (unsigned long)this_thread_id, acpi_ut_get_mutex_name(mutex_id))); status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, @@ -252,7 +252,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) if (ACPI_SUCCESS(status)) { ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %lX acquired Mutex [%s]\n", - (unsigned long) this_thread_id, + (unsigned long)this_thread_id, acpi_ut_get_mutex_name(mutex_id))); acpi_gbl_mutex_info[mutex_id].use_count++; @@ -260,7 +260,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) } else { ACPI_EXCEPTION((AE_INFO, status, "Thread %lX could not acquire Mutex [%X]", - (unsigned long) this_thread_id, mutex_id)); + (unsigned long)this_thread_id, mutex_id)); } return (status); @@ -287,7 +287,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) this_thread_id = acpi_os_get_thread_id(); ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %lX releasing Mutex [%s]\n", - (unsigned long) this_thread_id, + (unsigned long)this_thread_id, acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c index e8fe1ba6cc24..cbbd3315a1e2 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/utilities/utresrc.c @@ -46,7 +46,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utresrc") - #if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) /* * Strings used to decode resource descriptors. diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index de3276f4f468..e9a57806cd34 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -337,7 +337,6 @@ acpi_status acpi_terminate(void) } ACPI_EXPORT_SYMBOL(acpi_terminate) - #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -470,7 +469,6 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function) ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler) #endif /* ACPI_FUTURE_USAGE */ - /***************************************************************************** * * FUNCTION: acpi_purge_cached_objects diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index c7219663f2b9..f031b8732330 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -3,6 +3,7 @@ # menu "Serial ATA (prod) and Parallel ATA (experimental) drivers" + depends on HAS_IOMEM config ATA tristate "ATA device support" diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 0300e7f54cc4..2e18a63ead36 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -6,6 +6,7 @@ # menu "Auxiliary Display support" + depends on PARPORT config KS0108 tristate "KS0108 LCD Controller" diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 17ee97f3a99b..b4c8319138b2 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -444,8 +444,6 @@ config CDROM_PKTCDVD_WCACHE this option is dangerous unless the CD-RW media is known good, as we don't do deferred write error handling yet. -source "drivers/s390/block/Kconfig" - config ATA_OVER_ETH tristate "ATA over Ethernet support" depends on NET @@ -453,6 +451,8 @@ config ATA_OVER_ETH This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +source "drivers/s390/block/Kconfig" + endmenu endif diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2df42fdcdc91..abcafac64738 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -6,6 +6,7 @@ menu "Character devices" config VT bool "Virtual terminal" if EMBEDDED + depends on !S390 select INPUT default y if !VIOCONS ---help--- @@ -81,6 +82,7 @@ config VT_HW_CONSOLE_BINDING config SERIAL_NONSTANDARD bool "Non-standard serial port support" + depends on HAS_IOMEM ---help--- Say Y here if you have any non-standard serial boards -- boards which aren't supported using the standard "dumb" serial driver. @@ -765,7 +767,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH + depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -813,7 +815,7 @@ config SGI_IP27_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV + depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV && !S390 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -858,6 +860,7 @@ config COBALT_LCD config DTLK tristate "Double Talk PC internal speech card support" + depends on ISA help This driver is for the DoubleTalk PC, a speech synthesizer manufactured by RC Systems (<http://www.rcsys.com/>). It is also @@ -1043,7 +1046,7 @@ config HPET_MMAP config HANGCHECK_TIMER tristate "Hangcheck timer" - depends on X86 || IA64 || PPC64 + depends on X86 || IA64 || PPC64 || S390 help The hangcheck-timer module detects when the system has gone out to lunch past a certain margin. It can reboot the system @@ -1078,5 +1081,7 @@ config DEVPORT depends on ISA || PCI default y +source "drivers/s390/char/Kconfig" + endmenu diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index a6dcb2918157..b894f67fdf14 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -3,6 +3,8 @@ # menu "IPMI" + depends on HAS_IOMEM + config IPMI_HANDLER tristate 'IPMI top-level message handler' help diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 11089be0691b..dc4e1ff7f56f 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -3,6 +3,7 @@ # menu "TPM devices" + depends on HAS_IOMEM config TCG_TPM tristate "TPM Hardware Support" diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index f4c634504d1a..e678a33ea672 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -56,4 +56,26 @@ config CRYPTO_DEV_GEODE To compile this driver as a module, choose M here: the module will be called geode-aes. +config ZCRYPT + tristate "Support for PCI-attached cryptographic adapters" + depends on S390 + select ZCRYPT_MONOLITHIC if ZCRYPT="y" + default "m" + help + Select this option if you want to use a PCI-attached cryptographic + adapter like: + + PCI Cryptographic Accelerator (PCICA) + + PCI Cryptographic Coprocessor (PCICC) + + PCI-X Cryptographic Coprocessor (PCIXCC) + + Crypto Express2 Coprocessor (CEX2C) + + Crypto Express2 Accelerator (CEX2A) + +config ZCRYPT_MONOLITHIC + bool "Monolithic zcrypt module" + depends on ZCRYPT="m" + help + Select this option if you want to have a single module z90crypt.ko + that contains all parts of the crypto device driver (ap bus, + request router and all the card drivers). + endmenu diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 30d021d1a07c..72be6c63edfc 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -3,6 +3,7 @@ # menu "DMA Engine support" + depends on !S390 config DMA_ENGINE bool "Support for DMA engines" diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 4f0898400c6d..807c402df049 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -7,6 +7,7 @@ # menu 'EDAC - error detection and reporting (RAS) (EXPERIMENTAL)' + depends on HAS_IOMEM config EDAC tristate "EDAC core system error reporting (EXPERIMENTAL)" diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig new file mode 100644 index 000000000000..5932c72f9e42 --- /dev/null +++ b/drivers/firewire/Kconfig @@ -0,0 +1,61 @@ +# -*- shell-script -*- + +comment "An alternative FireWire stack is available with EXPERIMENTAL=y" + depends on EXPERIMENTAL=n + +config FIREWIRE + tristate "IEEE 1394 (FireWire) support (JUJU alternative stack, experimental)" + depends on EXPERIMENTAL + select CRC_ITU_T + help + IEEE 1394 describes a high performance serial bus, which is also + known as FireWire(tm) or i.Link(tm) and is used for connecting all + sorts of devices (most notably digital video cameras) to your + computer. + + If you have FireWire hardware and want to use it, say Y here. This + is the core support only, you will also need to select a driver for + your IEEE 1394 adapter. + + To compile this driver as a module, say M here: the module will be + called fw-core. + + This is the "JUJU" FireWire stack, an alternative implementation + designed for robustness and simplicity. You can build either this + stack, or the classic stack (the ieee1394 driver, ohci1394 etc.) + or both. + +config FIREWIRE_OHCI + tristate "Support for OHCI FireWire host controllers" + depends on PCI && FIREWIRE + help + Enable this driver if you have a FireWire controller based + on the OHCI specification. For all practical purposes, this + is the only chipset in use, so say Y here. + + To compile this driver as a module, say M here: The module will be + called fw-ohci. + + If you also build ohci1394 of the classic IEEE 1394 driver stack, + blacklist either ohci1394 or fw-ohci to let hotplug load the desired + driver. + +config FIREWIRE_SBP2 + tristate "Support for storage devices (SBP-2 protocol driver)" + depends on FIREWIRE && SCSI + help + This option enables you to use SBP-2 devices connected to a + FireWire bus. SBP-2 devices include storage devices like + harddisks and DVD drives, also some other FireWire devices + like scanners. + + To compile this driver as a module, say M here: The module will be + called fw-sbp2. + + You should also enable support for disks, CD-ROMs, etc. in the SCSI + configuration section. + + If you also build sbp2 of the classic IEEE 1394 driver stack, + blacklist either sbp2 or fw-sbp2 to let hotplug load the desired + driver. + diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile new file mode 100644 index 000000000000..fc7d59d4bce0 --- /dev/null +++ b/drivers/firewire/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the Linux IEEE 1394 implementation +# + +fw-core-y += fw-card.o fw-topology.o fw-transaction.o fw-iso.o \ + fw-device.o fw-cdev.o + +obj-$(CONFIG_FIREWIRE) += fw-core.o +obj-$(CONFIG_FIREWIRE_OHCI) += fw-ohci.o +obj-$(CONFIG_FIREWIRE_SBP2) += fw-sbp2.o diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c new file mode 100644 index 000000000000..636151a64add --- /dev/null +++ b/drivers/firewire/fw-card.c @@ -0,0 +1,560 @@ +/* + * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/device.h> +#include <linux/mutex.h> +#include <linux/crc-itu-t.h> +#include "fw-transaction.h" +#include "fw-topology.h" +#include "fw-device.h" + +int fw_compute_block_crc(u32 *block) +{ + __be32 be32_block[256]; + int i, length; + + length = (*block >> 16) & 0xff; + for (i = 0; i < length; i++) + be32_block[i] = cpu_to_be32(block[i + 1]); + *block |= crc_itu_t(0, (u8 *) be32_block, length * 4); + + return length; +} + +static DEFINE_MUTEX(card_mutex); +static LIST_HEAD(card_list); + +static LIST_HEAD(descriptor_list); +static int descriptor_count; + +#define BIB_CRC(v) ((v) << 0) +#define BIB_CRC_LENGTH(v) ((v) << 16) +#define BIB_INFO_LENGTH(v) ((v) << 24) + +#define BIB_LINK_SPEED(v) ((v) << 0) +#define BIB_GENERATION(v) ((v) << 4) +#define BIB_MAX_ROM(v) ((v) << 8) +#define BIB_MAX_RECEIVE(v) ((v) << 12) +#define BIB_CYC_CLK_ACC(v) ((v) << 16) +#define BIB_PMC ((1) << 27) +#define BIB_BMC ((1) << 28) +#define BIB_ISC ((1) << 29) +#define BIB_CMC ((1) << 30) +#define BIB_IMC ((1) << 31) + +static u32 * +generate_config_rom(struct fw_card *card, size_t *config_rom_length) +{ + struct fw_descriptor *desc; + static u32 config_rom[256]; + int i, j, length; + + /* + * Initialize contents of config rom buffer. On the OHCI + * controller, block reads to the config rom accesses the host + * memory, but quadlet read access the hardware bus info block + * registers. That's just crack, but it means we should make + * sure the contents of bus info block in host memory mathces + * the version stored in the OHCI registers. + */ + + memset(config_rom, 0, sizeof(config_rom)); + config_rom[0] = BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0); + config_rom[1] = 0x31333934; + + config_rom[2] = + BIB_LINK_SPEED(card->link_speed) | + BIB_GENERATION(card->config_rom_generation++ % 14 + 2) | + BIB_MAX_ROM(2) | + BIB_MAX_RECEIVE(card->max_receive) | + BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC; + config_rom[3] = card->guid >> 32; + config_rom[4] = card->guid; + + /* Generate root directory. */ + i = 5; + config_rom[i++] = 0; + config_rom[i++] = 0x0c0083c0; /* node capabilities */ + j = i + descriptor_count; + + /* Generate root directory entries for descriptors. */ + list_for_each_entry (desc, &descriptor_list, link) { + if (desc->immediate > 0) + config_rom[i++] = desc->immediate; + config_rom[i] = desc->key | (j - i); + i++; + j += desc->length; + } + + /* Update root directory length. */ + config_rom[5] = (i - 5 - 1) << 16; + + /* End of root directory, now copy in descriptors. */ + list_for_each_entry (desc, &descriptor_list, link) { + memcpy(&config_rom[i], desc->data, desc->length * 4); + i += desc->length; + } + + /* Calculate CRCs for all blocks in the config rom. This + * assumes that CRC length and info length are identical for + * the bus info block, which is always the case for this + * implementation. */ + for (i = 0; i < j; i += length + 1) + length = fw_compute_block_crc(config_rom + i); + + *config_rom_length = j; + + return config_rom; +} + +static void +update_config_roms(void) +{ + struct fw_card *card; + u32 *config_rom; + size_t length; + + list_for_each_entry (card, &card_list, link) { + config_rom = generate_config_rom(card, &length); + card->driver->set_config_rom(card, config_rom, length); + } +} + +int +fw_core_add_descriptor(struct fw_descriptor *desc) +{ + size_t i; + + /* + * Check descriptor is valid; the length of all blocks in the + * descriptor has to add up to exactly the length of the + * block. + */ + i = 0; + while (i < desc->length) + i += (desc->data[i] >> 16) + 1; + + if (i != desc->length) + return -EINVAL; + + mutex_lock(&card_mutex); + + list_add_tail(&desc->link, &descriptor_list); + descriptor_count++; + if (desc->immediate > 0) + descriptor_count++; + update_config_roms(); + + mutex_unlock(&card_mutex); + + return 0; +} +EXPORT_SYMBOL(fw_core_add_descriptor); + +void +fw_core_remove_descriptor(struct fw_descriptor *desc) +{ + mutex_lock(&card_mutex); + + list_del(&desc->link); + descriptor_count--; + if (desc->immediate > 0) + descriptor_count--; + update_config_roms(); + + mutex_unlock(&card_mutex); +} +EXPORT_SYMBOL(fw_core_remove_descriptor); + +static const char gap_count_table[] = { + 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40 +}; + +struct bm_data { + struct fw_transaction t; + struct { + __be32 arg; + __be32 data; + } lock; + u32 old; + int rcode; + struct completion done; +}; + +static void +complete_bm_lock(struct fw_card *card, int rcode, + void *payload, size_t length, void *data) +{ + struct bm_data *bmd = data; + + if (rcode == RCODE_COMPLETE) + bmd->old = be32_to_cpu(*(__be32 *) payload); + bmd->rcode = rcode; + complete(&bmd->done); +} + +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; + struct bm_data bmd; + unsigned long flags; + int root_id, new_root_id, irm_id, gap_count, generation, grace; + int do_reset = 0; + + spin_lock_irqsave(&card->lock, flags); + + generation = card->generation; + root = card->root_node->data; + root_id = card->root_node->node_id; + grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10)); + + if (card->bm_generation + 1 == generation || + (card->bm_generation != generation && grace)) { + /* + * This first step is to figure out who is IRM and + * then try to become bus manager. If the IRM is not + * well defined (e.g. does not have an active link + * layer or does not responds to our lock request, we + * will have to do a little vigilante bus management. + * In that case, we do a goto into the gap count logic + * so that when we do the reset, we still optimize the + * gap count. That could well save a reset in the + * next generation. + */ + + irm_id = card->irm_node->node_id; + if (!card->irm_node->link_on) { + new_root_id = card->local_node->node_id; + fw_notify("IRM has link off, making local node (%02x) root.\n", + new_root_id); + goto pick_me; + } + + bmd.lock.arg = cpu_to_be32(0x3f); + bmd.lock.data = cpu_to_be32(card->local_node->node_id); + + spin_unlock_irqrestore(&card->lock, flags); + + init_completion(&bmd.done); + fw_send_request(card, &bmd.t, TCODE_LOCK_COMPARE_SWAP, + irm_id, generation, + SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, + &bmd.lock, sizeof(bmd.lock), + complete_bm_lock, &bmd); + wait_for_completion(&bmd.done); + + if (bmd.rcode == RCODE_GENERATION) { + /* + * Another bus reset happened. Just return, + * the BM work has been rescheduled. + */ + return; + } + + if (bmd.rcode == RCODE_COMPLETE && bmd.old != 0x3f) + /* Somebody else is BM, let them do the work. */ + return; + + spin_lock_irqsave(&card->lock, flags); + if (bmd.rcode != RCODE_COMPLETE) { + /* + * The lock request failed, maybe the IRM + * isn't really IRM capable after all. Let's + * do a bus reset and pick the local node as + * root, and thus, IRM. + */ + new_root_id = card->local_node->node_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. + */ + spin_unlock_irqrestore(&card->lock, flags); + schedule_delayed_work(&card->work, DIV_ROUND_UP(HZ, 10)); + return; + } + + /* + * We're bus manager for this generation, so next step is to + * make sure we have an active cycle master and do gap count + * optimization. + */ + card->bm_generation = generation; + + if (root == NULL) { + /* + * Either link_on is false, or we failed to read the + * config rom. In either case, pick another root. + */ + new_root_id = card->local_node->node_id; + } else if (atomic_read(&root->state) != FW_DEVICE_RUNNING) { + /* + * If we haven't probed this device yet, bail out now + * and let's try again once that's done. + */ + spin_unlock_irqrestore(&card->lock, flags); + return; + } else if (root->config_rom[2] & BIB_CMC) { + /* + * FIXME: I suppose we should set the cmstr bit in the + * STATE_CLEAR register of this node, as described in + * 1394-1995, 8.4.2.6. Also, send out a force root + * packet for this node. + */ + new_root_id = root_id; + } else { + /* + * Current root has an active link layer and we + * successfully read the config rom, but it's not + * cycle master capable. + */ + new_root_id = card->local_node->node_id; + } + + pick_me: + /* Now figure out what gap count to set. */ + if (card->topology_type == FW_TOPOLOGY_A && + card->root_node->max_hops < ARRAY_SIZE(gap_count_table)) + gap_count = gap_count_table[card->root_node->max_hops]; + else + gap_count = 63; + + /* + * Finally, figure out if we should do a reset or not. If we've + * done less that 5 resets with the same physical topology and we + * have either a new root or a new gap count setting, let's do it. + */ + + if (card->bm_retries++ < 5 && + (card->gap_count != gap_count || new_root_id != root_id)) + do_reset = 1; + + spin_unlock_irqrestore(&card->lock, flags); + + if (do_reset) { + fw_notify("phy config: card %d, new root=%x, gap_count=%d\n", + 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); + } +} + +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) +{ + static atomic_t index = ATOMIC_INIT(-1); + + kref_init(&card->kref); + card->index = atomic_inc_return(&index); + card->driver = driver; + card->device = device; + card->current_tlabel = 0; + card->tlabel_mask = 0; + card->color = 0; + + INIT_LIST_HEAD(&card->transaction_list); + spin_lock_init(&card->lock); + setup_timer(&card->flush_timer, + flush_timer_callback, (unsigned long)card); + + card->local_node = NULL; + + INIT_DELAYED_WORK(&card->work, fw_card_bm_work); +} +EXPORT_SYMBOL(fw_card_initialize); + +int +fw_card_add(struct fw_card *card, + u32 max_receive, u32 link_speed, u64 guid) +{ + u32 *config_rom; + size_t length; + + card->max_receive = max_receive; + card->link_speed = link_speed; + card->guid = guid; + + /* Activate link_on bit and contender bit in our self ID packets.*/ + if (card->driver->update_phy_reg(card, 4, 0, + PHY_LINK_ACTIVE | PHY_CONTENDER) < 0) + return -EIO; + + /* + * The subsystem grabs a reference when the card is added and + * drops it when the driver calls fw_core_remove_card. + */ + fw_card_get(card); + + mutex_lock(&card_mutex); + config_rom = generate_config_rom(card, &length); + list_add_tail(&card->link, &card_list); + mutex_unlock(&card_mutex); + + return card->driver->enable(card, config_rom, length); +} +EXPORT_SYMBOL(fw_card_add); + + +/* + * The next few functions implements a dummy driver that use once a + * card driver shuts down an fw_card. This allows the driver to + * cleanly unload, as all IO to the card will be handled by the dummy + * driver instead of calling into the (possibly) unloaded module. The + * dummy driver just fails all IO. + */ + +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) +{ + return -ENODEV; +} + +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 + * driver, so this should never get called. + */ + BUG(); + return -1; +} + +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) +{ + packet->callback(packet, card, -ENODEV); +} + +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) +{ + return -ENODEV; +} + +static struct fw_card_driver dummy_driver = { + .name = "dummy", + .enable = dummy_enable, + .update_phy_reg = dummy_update_phy_reg, + .set_config_rom = dummy_set_config_rom, + .send_request = dummy_send_request, + .cancel_packet = dummy_cancel_packet, + .send_response = dummy_send_response, + .enable_phys_dma = dummy_enable_phys_dma, +}; + +void +fw_core_remove_card(struct fw_card *card) +{ + card->driver->update_phy_reg(card, 4, + PHY_LINK_ACTIVE | PHY_CONTENDER, 0); + fw_core_initiate_bus_reset(card, 1); + + mutex_lock(&card_mutex); + list_del(&card->link); + mutex_unlock(&card_mutex); + + /* Set up the dummy driver. */ + card->driver = &dummy_driver; + + fw_flush_transactions(card); + + fw_destroy_nodes(card); + + fw_card_put(card); +} +EXPORT_SYMBOL(fw_core_remove_card); + +struct fw_card * +fw_card_get(struct fw_card *card) +{ + kref_get(&card->kref); + + return card; +} +EXPORT_SYMBOL(fw_card_get); + +static void +release_card(struct kref *kref) +{ + struct fw_card *card = container_of(kref, struct fw_card, kref); + + kfree(card); +} + +/* + * An assumption for fw_card_put() is that the card driver allocates + * the fw_card struct with kalloc and that it has been shut down + * before the last ref is dropped. + */ +void +fw_card_put(struct fw_card *card) +{ + kref_put(&card->kref, release_card); +} +EXPORT_SYMBOL(fw_card_put); + +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; + + return card->driver->update_phy_reg(card, reg, 0, bit); +} +EXPORT_SYMBOL(fw_core_initiate_bus_reset); diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c new file mode 100644 index 000000000000..0fa5bd54c6a1 --- /dev/null +++ b/drivers/firewire/fw-cdev.c @@ -0,0 +1,961 @@ +/* + * Char device for device raw access + * + * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/wait.h> +#include <linux/errno.h> +#include <linux/device.h> +#include <linux/vmalloc.h> +#include <linux/poll.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/idr.h> +#include <linux/compat.h> +#include <linux/firewire-cdev.h> +#include <asm/uaccess.h> +#include "fw-transaction.h" +#include "fw-topology.h" +#include "fw-device.h" + +struct client; +struct client_resource { + struct list_head link; + void (*release)(struct client *client, struct client_resource *r); + u32 handle; +}; + +/* + * dequeue_event() just kfree()'s the event, so the event has to be + * the first field in the struct. + */ + +struct event { + struct { void *data; size_t size; } v[2]; + struct list_head link; +}; + +struct bus_reset { + struct event event; + struct fw_cdev_event_bus_reset reset; +}; + +struct response { + struct event event; + struct fw_transaction transaction; + struct client *client; + struct client_resource resource; + struct fw_cdev_event_response response; +}; + +struct iso_interrupt { + struct event event; + struct fw_cdev_event_iso_interrupt interrupt; +}; + +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 list_head link; +}; + +static inline void __user * +u64_to_uptr(__u64 value) +{ + return (void __user *)(unsigned long)value; +} + +static inline __u64 +uptr_to_u64(void __user *ptr) +{ + return (__u64)(unsigned long)ptr; +} + +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_from_devt(inode->i_rdev); + if (device == NULL) + return -ENODEV; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (client == NULL) + return -ENOMEM; + + client->device = fw_device_get(device); + INIT_LIST_HEAD(&client->event_list); + INIT_LIST_HEAD(&client->resource_list); + spin_lock_init(&client->lock); + init_waitqueue_head(&client->wait); + + file->private_data = client; + + spin_lock_irqsave(&device->card->lock, flags); + list_add_tail(&client->link, &device->client_list); + spin_unlock_irqrestore(&device->card->lock, flags); + + return 0; +} + +static void queue_event(struct client *client, struct event *event, + void *data0, size_t size0, void *data1, size_t size1) +{ + unsigned long flags; + + event->v[0].data = data0; + event->v[0].size = size0; + event->v[1].data = data1; + event->v[1].size = size1; + + spin_lock_irqsave(&client->lock, flags); + + list_add_tail(&event->link, &client->event_list); + wake_up_interruptible(&client->wait); + + spin_unlock_irqrestore(&client->lock, flags); +} + +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; + + retval = wait_event_interruptible(client->wait, + !list_empty(&client->event_list) || + fw_device_is_shutdown(client->device)); + if (retval < 0) + return retval; + + 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); + list_del(&event->link); + spin_unlock_irqrestore(&client->lock, flags); + + 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; + goto out; + } + total += size; + } + retval = total; + + out: + kfree(event); + + return retval; +} + +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); +} + +static void +fill_bus_reset_event(struct fw_cdev_event_bus_reset *event, + struct client *client) +{ + struct fw_card *card = client->device->card; + + event->closure = client->bus_reset_closure; + event->type = FW_CDEV_EVENT_BUS_RESET; + event->node_id = client->device->node_id; + event->local_node_id = card->local_node->node_id; + 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; + event->generation = card->generation; +} + +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); + + list_for_each_entry(c, &device->client_list, link) + callback(c); + + spin_unlock_irqrestore(&card->lock, flags); +} + +static void +queue_bus_reset_event(struct client *client) +{ + struct bus_reset *bus_reset; + + bus_reset = kzalloc(sizeof(*bus_reset), GFP_ATOMIC); + if (bus_reset == NULL) { + fw_notify("Out of memory when allocating bus reset event\n"); + return; + } + + fill_bus_reset_event(&bus_reset->reset, client); + + queue_event(client, &bus_reset->event, + &bus_reset->reset, sizeof(bus_reset->reset), NULL, 0); +} + +void fw_device_cdev_update(struct fw_device *device) +{ + for_each_client(device, queue_bus_reset_event); +} + +static void wake_up_client(struct client *client) +{ + wake_up_interruptible(&client->wait); +} + +void fw_device_cdev_remove(struct fw_device *device) +{ + for_each_client(device, wake_up_client); +} + +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; + + client->version = get_info->version; + get_info->version = FW_CDEV_VERSION; + + if (get_info->rom != 0) { + void __user *uptr = u64_to_uptr(get_info->rom); + size_t want = get_info->rom_length; + size_t have = client->device->config_rom_length * 4; + + if (copy_to_user(uptr, client->device->config_rom, + min(want, have))) + return -EFAULT; + } + get_info->rom_length = client->device->config_rom_length * 4; + + 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); + + fill_bus_reset_event(&bus_reset, client); + if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset))) + return -EFAULT; + } + + get_info->card = client->device->card->index; + + return 0; +} + +static void +add_client_resource(struct client *client, struct client_resource *resource) +{ + unsigned long flags; + + spin_lock_irqsave(&client->lock, flags); + list_add_tail(&resource->link, &client->resource_list); + resource->handle = client->resource_handle++; + spin_unlock_irqrestore(&client->lock, flags); +} + +static int +release_client_resource(struct client *client, u32 handle, + 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); + + if (&r->link == &client->resource_list) + return -EINVAL; + + if (resource) + *resource = r; + else + r->release(client, r); + + return 0; +} + +static void +release_transaction(struct client *client, struct client_resource *resource) +{ + struct response *response = + container_of(resource, struct response, resource); + + fw_cancel_transaction(client->device->card, &response->transaction); +} + +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; + unsigned long flags; + + if (length < response->response.length) + response->response.length = length; + if (rcode == RCODE_COMPLETE) + memcpy(response->response.data, payload, + response->response.length); + + spin_lock_irqsave(&client->lock, flags); + list_del(&response->resource.link); + spin_unlock_irqrestore(&client->lock, flags); + + response->response.type = FW_CDEV_EVENT_RESPONSE; + response->response.rcode = rcode; + queue_event(client, &response->event, + &response->response, sizeof(response->response), + response->response.data, response->response.length); +} + +static ssize_t ioctl_send_request(struct client *client, void *buffer) +{ + struct fw_device *device = client->device; + struct fw_cdev_send_request *request = buffer; + struct response *response; + + /* What is the biggest size we'll accept, really? */ + if (request->length > 4096) + return -EINVAL; + + response = kmalloc(sizeof(*response) + request->length, GFP_KERNEL); + if (response == NULL) + return -ENOMEM; + + response->client = client; + response->response.length = request->length; + response->response.closure = request->closure; + + if (request->data && + copy_from_user(response->response.data, + u64_to_uptr(request->data), request->length)) { + kfree(response); + return -EFAULT; + } + + response->resource.release = release_transaction; + add_client_resource(client, &response->resource); + + fw_send_request(device->card, &response->transaction, + request->tcode & 0x1f, + device->node->node_id, + request->generation, + device->node->max_speed, + request->offset, + response->response.data, request->length, + complete_transaction, response); + + if (request->data) + return sizeof(request) + request->length; + else + return sizeof(request); +} + +struct address_handler { + struct fw_address_handler handler; + __u64 closure; + struct client *client; + struct client_resource resource; +}; + +struct request { + struct fw_request *request; + void *data; + size_t length; + struct client_resource resource; +}; + +struct request_event { + struct event event; + struct fw_cdev_event_request request; +}; + +static void +release_request(struct client *client, struct client_resource *resource) +{ + struct request *request = + container_of(resource, struct request, resource); + + fw_send_response(client->device->card, request->request, + RCODE_CONFLICT_ERROR); + kfree(request); +} + +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) +{ + struct address_handler *handler = callback_data; + struct request *request; + struct request_event *e; + struct client *client = handler->client; + + request = kmalloc(sizeof(*request), 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; + } + + request->request = r; + request->data = payload; + request->length = length; + + request->resource.release = release_request; + add_client_resource(client, &request->resource); + + 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.closure = handler->closure; + + queue_event(client, &e->event, + &e->request, sizeof(e->request), payload, length); +} + +static void +release_address_handler(struct client *client, + struct client_resource *resource) +{ + struct address_handler *handler = + container_of(resource, struct address_handler, resource); + + fw_core_remove_address_handler(&handler->handler); + kfree(handler); +} + +static int ioctl_allocate(struct client *client, void *buffer) +{ + struct fw_cdev_allocate *request = buffer; + struct address_handler *handler; + struct fw_address_region region; + + handler = kmalloc(sizeof(*handler), GFP_KERNEL); + if (handler == 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, ®ion) < 0) { + kfree(handler); + return -EBUSY; + } + + handler->resource.release = release_address_handler; + add_client_resource(client, &handler->resource); + request->handle = handler->resource.handle; + + return 0; +} + +static int ioctl_deallocate(struct client *client, void *buffer) +{ + struct fw_cdev_deallocate *request = buffer; + + return release_client_resource(client, request->handle, 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; + + if (release_client_resource(client, request->handle, &resource) < 0) + return -EINVAL; + r = container_of(resource, struct request, resource); + if (request->length < r->length) + r->length = request->length; + if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) + return -EFAULT; + + fw_send_response(client->device->card, r->request, request->rcode); + kfree(r); + + return 0; +} + +static int ioctl_initiate_bus_reset(struct client *client, void *buffer) +{ + struct fw_cdev_initiate_bus_reset *request = buffer; + int short_reset; + + short_reset = (request->type == FW_CDEV_SHORT_RESET); + + 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); + + fw_core_remove_descriptor(&descriptor->d); + kfree(descriptor); +} + +static int ioctl_add_descriptor(struct client *client, void *buffer) +{ + struct fw_cdev_add_descriptor *request = buffer; + struct descriptor *descriptor; + int retval; + + if (request->length > 256) + return -EINVAL; + + descriptor = + kmalloc(sizeof(*descriptor) + request->length * 4, GFP_KERNEL); + if (descriptor == NULL) + return -ENOMEM; + + if (copy_from_user(descriptor->data, + u64_to_uptr(request->data), request->length * 4)) { + kfree(descriptor); + return -EFAULT; + } + + descriptor->d.length = request->length; + descriptor->d.immediate = request->immediate; + descriptor->d.key = request->key; + descriptor->d.data = descriptor->data; + + retval = fw_core_add_descriptor(&descriptor->d); + if (retval < 0) { + kfree(descriptor); + return retval; + } + + descriptor->resource.release = release_descriptor; + add_client_resource(client, &descriptor->resource); + request->handle = descriptor->resource.handle; + + return 0; +} + +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); +} + +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 *interrupt; + + interrupt = kzalloc(sizeof(*interrupt) + header_length, GFP_ATOMIC); + if (interrupt == NULL) + return; + + interrupt->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; + interrupt->interrupt.closure = client->iso_closure; + interrupt->interrupt.cycle = cycle; + interrupt->interrupt.header_length = header_length; + memcpy(interrupt->interrupt.header, header, header_length); + queue_event(client, &interrupt->event, + &interrupt->interrupt, + sizeof(interrupt->interrupt) + header_length, NULL, 0); +} + +static int ioctl_create_iso_context(struct client *client, void *buffer) +{ + struct fw_cdev_create_iso_context *request = buffer; + + if (request->channel > 63) + return -EINVAL; + + switch (request->type) { + case FW_ISO_CONTEXT_RECEIVE: + if (request->header_size < 4 || (request->header_size & 3)) + return -EINVAL; + + break; + + case FW_ISO_CONTEXT_TRANSMIT: + if (request->speed > SCODE_3200) + return -EINVAL; + + break; + + default: + return -EINVAL; + } + + client->iso_closure = request->closure; + client->iso_context = fw_iso_context_create(client->device->card, + request->type, + request->channel, + request->speed, + request->header_size, + iso_callback, client); + if (IS_ERR(client->iso_context)) + return PTR_ERR(client->iso_context); + + /* We only support one context at this time. */ + request->handle = 0; + + return 0; +} + +static int ioctl_queue_iso(struct client *client, void *buffer) +{ + struct fw_cdev_queue_iso *request = buffer; + struct fw_cdev_iso_packet __user *p, *end, *next; + struct fw_iso_context *ctx = client->iso_context; + unsigned long payload, buffer_end, header_length; + int count; + struct { + struct fw_iso_packet packet; + u8 header[256]; + } u; + + if (ctx == NULL || request->handle != 0) + return -EINVAL; + + /* + * If the user passes a non-NULL data pointer, has mmap()'ed + * the iso buffer, and the pointer points inside the buffer, + * we setup the payload pointers accordingly. Otherwise we + * set them both to 0, which will still let packets with + * payload_length == 0 through. In other words, if no packets + * use the indirect payload, the iso buffer need not be mapped + * and the request->data pointer is ignored. + */ + + payload = (unsigned long)request->data - client->vm_start; + buffer_end = client->buffer.page_count << PAGE_SHIFT; + if (request->data == 0 || client->buffer.pages == NULL || + payload >= buffer_end) { + payload = 0; + buffer_end = 0; + } + + if (!access_ok(VERIFY_READ, request->packets, request->size)) + return -EFAULT; + + p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets); + end = (void __user *)p + request->size; + count = 0; + while (p < end) { + if (__copy_from_user(&u.packet, p, sizeof(*p))) + return -EFAULT; + + if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) { + header_length = u.packet.header_length; + } else { + /* + * We require that header_length is a multiple of + * the fixed header size, ctx->header_size. + */ + if (ctx->header_size == 0) { + if (u.packet.header_length > 0) + return -EINVAL; + } else if (u.packet.header_length % ctx->header_size != 0) { + return -EINVAL; + } + header_length = 0; + } + + next = (struct fw_cdev_iso_packet __user *) + &p->header[header_length / 4]; + if (next > end) + return -EINVAL; + if (__copy_from_user + (u.packet.header, p->header, header_length)) + return -EFAULT; + if (u.packet.skip && ctx->type == FW_ISO_CONTEXT_TRANSMIT && + u.packet.header_length + u.packet.payload_length > 0) + return -EINVAL; + if (payload + u.packet.payload_length > buffer_end) + return -EINVAL; + + if (fw_iso_context_queue(ctx, &u.packet, + &client->buffer, payload)) + break; + + p = next; + payload += u.packet.payload_length; + count++; + } + + request->size -= uptr_to_u64(p) - request->packets; + request->packets = uptr_to_u64(p); + request->data = client->vm_start + payload; + + return count; +} + +static int ioctl_start_iso(struct client *client, void *buffer) +{ + struct fw_cdev_start_iso *request = buffer; + + if (request->handle != 0) + return -EINVAL; + if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) { + if (request->tags == 0 || request->tags > 15) + return -EINVAL; + + if (request->sync > 15) + return -EINVAL; + } + + return fw_iso_context_start(client->iso_context, request->cycle, + request->sync, request->tags); +} + +static int ioctl_stop_iso(struct client *client, void *buffer) +{ + struct fw_cdev_stop_iso *request = buffer; + + if (request->handle != 0) + return -EINVAL; + + return fw_iso_context_stop(client->iso_context); +} + +static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { + ioctl_get_info, + ioctl_send_request, + ioctl_allocate, + ioctl_deallocate, + ioctl_send_response, + ioctl_initiate_bus_reset, + ioctl_add_descriptor, + ioctl_remove_descriptor, + ioctl_create_iso_context, + ioctl_queue_iso, + ioctl_start_iso, + ioctl_stop_iso, +}; + +static int +dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg) +{ + char buffer[256]; + int retval; + + if (_IOC_TYPE(cmd) != '#' || + _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers)) + return -EINVAL; + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + if (_IOC_SIZE(cmd) > sizeof(buffer) || + copy_from_user(buffer, arg, _IOC_SIZE(cmd))) + return -EFAULT; + } + + retval = ioctl_handlers[_IOC_NR(cmd)](client, buffer); + if (retval < 0) + return retval; + + if (_IOC_DIR(cmd) & _IOC_READ) { + if (_IOC_SIZE(cmd) > sizeof(buffer) || + copy_to_user(arg, buffer, _IOC_SIZE(cmd))) + return -EFAULT; + } + + return 0; +} + +static long +fw_device_op_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct client *client = file->private_data; + + return dispatch_ioctl(client, cmd, (void __user *) arg); +} + +#ifdef CONFIG_COMPAT +static long +fw_device_op_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct client *client = file->private_data; + + return dispatch_ioctl(client, cmd, compat_ptr(arg)); +} +#endif + +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; + + /* FIXME: We could support multiple buffers, but we don't. */ + if (client->buffer.pages != NULL) + return -EBUSY; + + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + if (vma->vm_start & ~PAGE_MASK) + return -EINVAL; + + client->vm_start = vma->vm_start; + size = vma->vm_end - vma->vm_start; + page_count = size >> PAGE_SHIFT; + if (size & ~PAGE_MASK) + return -EINVAL; + + if (vma->vm_flags & VM_WRITE) + direction = DMA_TO_DEVICE; + else + direction = DMA_FROM_DEVICE; + + retval = fw_iso_buffer_init(&client->buffer, client->device->card, + page_count, direction); + if (retval < 0) + return retval; + + retval = fw_iso_buffer_map(&client->buffer, vma); + if (retval < 0) + fw_iso_buffer_destroy(&client->buffer, client->device->card); + + return retval; +} + +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); + + 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); + + /* + * FIXME: We should wait for the async tasklets to stop + * running before freeing the memory. + */ + + 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); + + return 0; +} + +static unsigned int fw_device_op_poll(struct file *file, poll_table * pt) +{ + struct client *client = file->private_data; + unsigned int mask = 0; + + poll_wait(file, &client->wait, pt); + + if (fw_device_is_shutdown(client->device)) + mask |= POLLHUP | POLLERR; + if (!list_empty(&client->event_list)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +const struct file_operations fw_device_ops = { + .owner = THIS_MODULE, + .open = fw_device_op_open, + .read = fw_device_op_read, + .unlocked_ioctl = fw_device_op_ioctl, + .poll = fw_device_op_poll, + .release = fw_device_op_release, + .mmap = fw_device_op_mmap, + +#ifdef CONFIG_COMPAT + .compat_ioctl = fw_device_op_compat_ioctl, +#endif +}; diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c new file mode 100644 index 000000000000..c1ce465d9710 --- /dev/null +++ b/drivers/firewire/fw-device.c @@ -0,0 +1,813 @@ +/* + * Device probing and sysfs code. + * + * Copyright (C) 2005-2006 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/module.h> +#include <linux/wait.h> +#include <linux/errno.h> +#include <linux/kthread.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/idr.h> +#include <linux/rwsem.h> +#include <asm/semaphore.h> +#include <linux/ctype.h> +#include "fw-transaction.h" +#include "fw-topology.h" +#include "fw-device.h" + +void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p) +{ + ci->p = p + 1; + ci->end = ci->p + (p[0] >> 16); +} +EXPORT_SYMBOL(fw_csr_iterator_init); + +int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value) +{ + *key = *ci->p >> 24; + *value = *ci->p & 0xffffff; + + return ci->p++ < ci->end; +} +EXPORT_SYMBOL(fw_csr_iterator_next); + +static int is_fw_unit(struct device *dev); + +static int match_unit_directory(u32 * directory, const struct fw_device_id *id) +{ + struct fw_csr_iterator ci; + int key, value, match; + + match = 0; + fw_csr_iterator_init(&ci, directory); + while (fw_csr_iterator_next(&ci, &key, &value)) { + if (key == CSR_VENDOR && value == id->vendor) + match |= FW_MATCH_VENDOR; + if (key == CSR_MODEL && value == id->model) + match |= FW_MATCH_MODEL; + if (key == CSR_SPECIFIER_ID && value == id->specifier_id) + match |= FW_MATCH_SPECIFIER_ID; + if (key == CSR_VERSION && value == id->version) + match |= FW_MATCH_VERSION; + } + + return (match & id->match_flags) == id->match_flags; +} + +static int fw_unit_match(struct device *dev, struct device_driver *drv) +{ + struct fw_unit *unit = fw_unit(dev); + struct fw_driver *driver = fw_driver(drv); + int i; + + /* We only allow binding to fw_units. */ + if (!is_fw_unit(dev)) + return 0; + + for (i = 0; driver->id_table[i].match_flags != 0; i++) { + if (match_unit_directory(unit->directory, &driver->id_table[i])) + return 1; + } + + return 0; +} + +static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) +{ + struct fw_device *device = fw_device(unit->device.parent); + struct fw_csr_iterator ci; + + int key, value; + int vendor = 0; + int model = 0; + int specifier_id = 0; + int version = 0; + + fw_csr_iterator_init(&ci, &device->config_rom[5]); + while (fw_csr_iterator_next(&ci, &key, &value)) { + switch (key) { + case CSR_VENDOR: + vendor = value; + break; + case CSR_MODEL: + model = value; + break; + } + } + + fw_csr_iterator_init(&ci, unit->directory); + while (fw_csr_iterator_next(&ci, &key, &value)) { + switch (key) { + case CSR_SPECIFIER_ID: + specifier_id = value; + break; + case CSR_VERSION: + version = value; + break; + } + } + + return snprintf(buffer, buffer_size, + "ieee1394:ven%08Xmo%08Xsp%08Xver%08X", + vendor, model, specifier_id, version); +} + +static int +fw_unit_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct fw_unit *unit = fw_unit(dev); + char modalias[64]; + int length = 0; + int i = 0; + + get_modalias(unit, modalias, sizeof(modalias)); + + if (add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "MODALIAS=%s", modalias)) + return -ENOMEM; + + envp[i] = NULL; + + return 0; +} + +struct bus_type fw_bus_type = { + .name = "firewire", + .match = fw_unit_match, +}; +EXPORT_SYMBOL(fw_bus_type); + +struct fw_device *fw_device_get(struct fw_device *device) +{ + get_device(&device->device); + + return device; +} + +void fw_device_put(struct fw_device *device) +{ + put_device(&device->device); +} + +static void fw_device_release(struct device *dev) +{ + struct fw_device *device = fw_device(dev); + unsigned long flags; + + /* + * Take the card lock so we don't set this to NULL while a + * FW_NODE_UPDATED callback is being handled. + */ + spin_lock_irqsave(&device->card->lock, flags); + device->node->data = NULL; + spin_unlock_irqrestore(&device->card->lock, flags); + + fw_node_put(device->node); + fw_card_put(device->card); + kfree(device->config_rom); + kfree(device); +} + +int fw_device_enable_phys_dma(struct fw_device *device) +{ + return device->card->driver->enable_phys_dma(device->card, + device->node_id, + device->generation); +} +EXPORT_SYMBOL(fw_device_enable_phys_dma); + +struct config_rom_attribute { + struct device_attribute attr; + u32 key; +}; + +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); + struct fw_csr_iterator ci; + u32 *dir; + int key, value; + + if (is_fw_unit(dev)) + dir = fw_unit(dev)->directory; + else + dir = fw_device(dev)->config_rom + 5; + + fw_csr_iterator_init(&ci, dir); + while (fw_csr_iterator_next(&ci, &key, &value)) + if (attr->key == key) + return snprintf(buf, buf ? PAGE_SIZE : 0, + "0x%06x\n", value); + + return -ENOENT; +} + +#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) +{ + struct config_rom_attribute *attr = + container_of(dattr, struct config_rom_attribute, attr); + struct fw_csr_iterator ci; + u32 *dir, *block = NULL, *p, *end; + int length, key, value, last_key = 0; + char *b; + + if (is_fw_unit(dev)) + dir = fw_unit(dev)->directory; + else + dir = fw_device(dev)->config_rom + 5; + + fw_csr_iterator_init(&ci, dir); + while (fw_csr_iterator_next(&ci, &key, &value)) { + if (attr->key == last_key && + key == (CSR_DESCRIPTOR | CSR_LEAF)) + block = ci.p - 1 + value; + last_key = key; + } + + if (block == NULL) + return -ENOENT; + + length = min(block[0] >> 16, 256U); + if (length < 3) + return -ENOENT; + + if (block[1] != 0 || block[2] != 0) + /* Unknown encoding. */ + return -ENOENT; + + if (buf == NULL) + return length * 4; + + b = buf; + end = &block[length + 1]; + for (p = &block[3]; p < end; p++, b += 4) + * (u32 *) b = (__force u32) __cpu_to_be32(*p); + + /* Strip trailing whitespace and add newline. */ + while (b--, (isspace(*b) || *b == '\0') && b > buf); + strcpy(b + 1, "\n"); + + return b + 2 - buf; +} + +#define TEXT_LEAF_ATTR(name, key) \ + { __ATTR(name, S_IRUGO, show_text_leaf, NULL), key } + +static struct config_rom_attribute config_rom_attributes[] = { + IMMEDIATE_ATTR(vendor, CSR_VENDOR), + IMMEDIATE_ATTR(hardware_version, CSR_HARDWARE_VERSION), + IMMEDIATE_ATTR(specifier_id, CSR_SPECIFIER_ID), + IMMEDIATE_ATTR(version, CSR_VERSION), + IMMEDIATE_ATTR(model, CSR_MODEL), + TEXT_LEAF_ATTR(vendor_name, CSR_VENDOR), + TEXT_LEAF_ATTR(model_name, CSR_MODEL), + 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) +{ + struct device_attribute *attr; + int i, j; + + for (j = 0; attrs[j].attr.name != NULL; j++) + group->attrs[j] = &attrs[j].attr; + + for (i = 0; i < ARRAY_SIZE(config_rom_attributes); i++) { + attr = &config_rom_attributes[i].attr; + if (attr->show(dev, attr, NULL) < 0) + continue; + group->attrs[j++] = &attr->attr; + } + + BUG_ON(j >= ARRAY_SIZE(group->attrs)); + group->attrs[j++] = NULL; + group->groups[0] = &group->group; + group->groups[1] = NULL; + group->group.attrs = group->attrs; + dev->groups = group->groups; +} + +static ssize_t +modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fw_unit *unit = fw_unit(dev); + int length; + + length = get_modalias(unit, buf, PAGE_SIZE); + strcpy(buf + length, "\n"); + + return length + 1; +} + +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); + + return snprintf(buf, PAGE_SIZE, "%d\n", + (int)(unit->directory - device->config_rom)); +} + +static struct device_attribute fw_unit_attributes[] = { + __ATTR_RO(modalias), + __ATTR_RO(rom_index), + __ATTR_NULL, +}; + +static ssize_t +config_rom_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fw_device *device = fw_device(dev); + + memcpy(buf, device->config_rom, device->config_rom_length * 4); + + return device->config_rom_length * 4; +} + +static ssize_t +guid_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fw_device *device = fw_device(dev); + u64 guid; + + guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4]; + + return snprintf(buf, PAGE_SIZE, "0x%016llx\n", + (unsigned long long)guid); +} + +static struct device_attribute fw_device_attributes[] = { + __ATTR_RO(config_rom), + __ATTR_RO(guid), + __ATTR_NULL, +}; + +struct read_quadlet_callback_data { + struct completion done; + int rcode; + u32 data; +}; + +static void +complete_transaction(struct fw_card *card, int rcode, + void *payload, size_t length, void *data) +{ + struct read_quadlet_callback_data *callback_data = data; + + if (rcode == RCODE_COMPLETE) + callback_data->data = be32_to_cpu(*(__be32 *)payload); + callback_data->rcode = rcode; + complete(&callback_data->done); +} + +static int read_rom(struct fw_device *device, int index, u32 * data) +{ + struct read_quadlet_callback_data callback_data; + struct fw_transaction t; + u64 offset; + + init_completion(&callback_data.done); + + offset = 0xfffff0000400ULL + index * 4; + fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, + device->node_id, + device->generation, SCODE_100, + offset, NULL, 4, complete_transaction, &callback_data); + + wait_for_completion(&callback_data.done); + + *data = callback_data.data; + + return callback_data.rcode; +} + +static int read_bus_info_block(struct fw_device *device) +{ + static u32 rom[256]; + u32 stack[16], sp, key; + int i, end, length; + + /* First read the bus info block. */ + for (i = 0; i < 5; i++) { + if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) + return -1; + /* + * As per IEEE1212 7.2, during power-up, devices can + * reply with a 0 for the first quadlet of the config + * rom to indicate that they are booting (for example, + * if the firmware is on the disk of a external + * harddisk). In that case we just fail, and the + * retry mechanism will try again later. + */ + if (i == 0 && rom[i] == 0) + return -1; + } + + /* + * Now parse the config rom. The config rom is a recursive + * directory structure so we parse it using a stack of + * references to the blocks that make up the structure. We + * push a reference to the root directory on the stack to + * start things off. + */ + length = i; + sp = 0; + stack[sp++] = 0xc0000005; + while (sp > 0) { + /* + * Pop the next block reference of the stack. The + * lower 24 bits is the offset into the config rom, + * the upper 8 bits are the type of the reference the + * block. + */ + key = stack[--sp]; + i = key & 0xffffff; + if (i >= ARRAY_SIZE(rom)) + /* + * The reference points outside the standard + * config rom area, something's fishy. + */ + return -1; + + /* Read header quadlet for the block to get the length. */ + if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) + return -1; + end = i + (rom[i] >> 16) + 1; + i++; + if (end > ARRAY_SIZE(rom)) + /* + * This block extends outside standard config + * area (and the array we're reading it + * into). That's broken, so ignore this + * device. + */ + return -1; + + /* + * Now read in the block. If this is a directory + * block, check the entries as we read them to see if + * it references another block, and push it in that case. + */ + while (i < end) { + if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) + return -1; + if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && + sp < ARRAY_SIZE(stack)) + stack[sp++] = i + rom[i]; + i++; + } + if (length < i) + length = i; + } + + device->config_rom = kmalloc(length * 4, GFP_KERNEL); + if (device->config_rom == NULL) + return -1; + memcpy(device->config_rom, rom, length * 4); + device->config_rom_length = length; + + return 0; +} + +static void fw_unit_release(struct device *dev) +{ + struct fw_unit *unit = fw_unit(dev); + + kfree(unit); +} + +static struct device_type fw_unit_type = { + .uevent = fw_unit_uevent, + .release = fw_unit_release, +}; + +static int is_fw_unit(struct device *dev) +{ + return dev->type == &fw_unit_type; +} + +static void create_units(struct fw_device *device) +{ + struct fw_csr_iterator ci; + struct fw_unit *unit; + int key, value, i; + + i = 0; + fw_csr_iterator_init(&ci, &device->config_rom[5]); + while (fw_csr_iterator_next(&ci, &key, &value)) { + if (key != (CSR_UNIT | CSR_DIRECTORY)) + continue; + + /* + * Get the address of the unit directory and try to + * match the drivers id_tables against it. + */ + unit = kzalloc(sizeof(*unit), GFP_KERNEL); + if (unit == NULL) { + fw_error("failed to allocate memory for unit\n"); + continue; + } + + unit->directory = ci.p + value - 1; + unit->device.bus = &fw_bus_type; + unit->device.type = &fw_unit_type; + unit->device.parent = &device->device; + snprintf(unit->device.bus_id, sizeof(unit->device.bus_id), + "%s.%d", device->device.bus_id, i++); + + init_fw_attribute_group(&unit->device, + fw_unit_attributes, + &unit->attribute_group); + if (device_register(&unit->device) < 0) + goto skip_unit; + + continue; + + skip_unit: + kfree(unit); + } +} + +static int shutdown_unit(struct device *device, void *data) +{ + device_unregister(device); + + return 0; +} + +static DECLARE_RWSEM(idr_rwsem); +static DEFINE_IDR(fw_device_idr); +int fw_cdev_major; + +struct fw_device *fw_device_from_devt(dev_t devt) +{ + struct fw_device *device; + + down_read(&idr_rwsem); + device = idr_find(&fw_device_idr, MINOR(devt)); + up_read(&idr_rwsem); + + return device; +} + +static void fw_device_shutdown(struct work_struct *work) +{ + struct fw_device *device = + container_of(work, struct fw_device, work.work); + int minor = MINOR(device->device.devt); + + down_write(&idr_rwsem); + idr_remove(&fw_device_idr, minor); + up_write(&idr_rwsem); + + fw_device_cdev_remove(device); + device_for_each_child(&device->device, NULL, shutdown_unit); + device_unregister(&device->device); +} + +static struct device_type fw_device_type = { + .release = fw_device_release, +}; + +/* + * These defines control the retry behavior for reading the config + * rom. It shouldn't be necessary to tweak these; if the device + * doesn't respond to a config rom read within 10 seconds, it's not + * going to respond at all. As for the initial delay, a lot of + * devices will be able to respond within half a second after bus + * reset. On the other hand, it's not really worth being more + * aggressive than that, since it scales pretty well; if 10 devices + * are plugged in, they're all getting read within one second. + */ + +#define MAX_RETRIES 10 +#define RETRY_DELAY (3 * HZ) +#define INITIAL_DELAY (HZ / 2) + +static void fw_device_init(struct work_struct *work) +{ + struct fw_device *device = + container_of(work, struct fw_device, work.work); + int minor, err; + + /* + * All failure paths here set node->data to NULL, so that we + * don't try to do device_for_each_child() on a kfree()'d + * device. + */ + + if (read_bus_info_block(device) < 0) { + if (device->config_rom_retries < MAX_RETRIES) { + device->config_rom_retries++; + schedule_delayed_work(&device->work, RETRY_DELAY); + } else { + fw_notify("giving up on config rom for node id %x\n", + device->node_id); + if (device->node == device->card->root_node) + schedule_delayed_work(&device->card->work, 0); + fw_device_release(&device->device); + } + return; + } + + err = -ENOMEM; + down_write(&idr_rwsem); + if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) + err = idr_get_new(&fw_device_idr, device, &minor); + up_write(&idr_rwsem); + if (err < 0) + goto error; + + device->device.bus = &fw_bus_type; + device->device.type = &fw_device_type; + device->device.parent = device->card->device; + device->device.devt = MKDEV(fw_cdev_major, minor); + snprintf(device->device.bus_id, sizeof(device->device.bus_id), + "fw%d", minor); + + init_fw_attribute_group(&device->device, + fw_device_attributes, + &device->attribute_group); + if (device_add(&device->device)) { + fw_error("Failed to add device.\n"); + goto error_with_cdev; + } + + create_units(device); + + /* + * Transition the device to running state. If it got pulled + * out from under us while we did the intialization work, we + * have to shut down the device again here. Normally, though, + * fw_node_event will be responsible for shutting it down when + * necessary. We have to use the atomic cmpxchg here to avoid + * racing with the FW_NODE_DESTROYED case in + * fw_node_event(). + */ + if (atomic_cmpxchg(&device->state, + FW_DEVICE_INITIALIZING, + FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) + fw_device_shutdown(&device->work.work); + else + fw_notify("created new fw device %s (%d config rom retries)\n", + device->device.bus_id, device->config_rom_retries); + + /* + * Reschedule the IRM work if we just finished reading the + * root node config rom. If this races with a bus reset we + * just end up running the IRM work a couple of extra times - + * pretty harmless. + */ + if (device->node == device->card->root_node) + schedule_delayed_work(&device->card->work, 0); + + return; + + error_with_cdev: + down_write(&idr_rwsem); + idr_remove(&fw_device_idr, minor); + up_write(&idr_rwsem); + error: + put_device(&device->device); +} + +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); +} + +void fw_node_event(struct fw_card *card, struct fw_node *node, int event) +{ + struct fw_device *device; + + switch (event) { + case FW_NODE_CREATED: + case FW_NODE_LINK_ON: + if (!node->link_on) + break; + + device = kzalloc(sizeof(*device), GFP_ATOMIC); + if (device == NULL) + break; + + /* + * Do minimal intialization of the device here, the + * rest will happen in fw_device_init(). We need the + * card and node so we can read the config rom and we + * need to do device_initialize() now so + * device_for_each_child() in FW_NODE_UPDATED is + * doesn't freak out. + */ + device_initialize(&device->device); + atomic_set(&device->state, FW_DEVICE_INITIALIZING); + device->card = fw_card_get(card); + device->node = fw_node_get(node); + device->node_id = node->node_id; + device->generation = card->generation; + INIT_LIST_HEAD(&device->client_list); + + /* + * Set the node data to point back to this device so + * FW_NODE_UPDATED callbacks can update the node_id + * and generation for the device. + */ + node->data = device; + + /* + * Many devices are slow to respond after bus resets, + * especially if they are bus powered and go through + * power-up after getting plugged in. We schedule the + * first config rom scan half a second after bus reset. + */ + INIT_DELAYED_WORK(&device->work, fw_device_init); + schedule_delayed_work(&device->work, INITIAL_DELAY); + break; + + case FW_NODE_UPDATED: + if (!node->link_on || node->data == NULL) + break; + + device = node->data; + device->node_id = node->node_id; + device->generation = card->generation; + if (atomic_read(&device->state) == FW_DEVICE_RUNNING) { + PREPARE_DELAYED_WORK(&device->work, fw_device_update); + schedule_delayed_work(&device->work, 0); + } + break; + + case FW_NODE_DESTROYED: + case FW_NODE_LINK_OFF: + if (!node->data) + break; + + /* + * Destroy the device associated with the node. There + * are two cases here: either the device is fully + * initialized (FW_DEVICE_RUNNING) or we're in the + * process of reading its config rom + * (FW_DEVICE_INITIALIZING). If it is fully + * initialized we can reuse device->work to schedule a + * full fw_device_shutdown(). If not, there's work + * scheduled to read it's config rom, and we just put + * the device in shutdown state to have that code fail + * to create the device. + */ + device = node->data; + if (atomic_xchg(&device->state, + FW_DEVICE_SHUTDOWN) == FW_DEVICE_RUNNING) { + PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); + schedule_delayed_work(&device->work, 0); + } + break; + } +} diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h new file mode 100644 index 000000000000..0ba9d64ccf4c --- /dev/null +++ b/drivers/firewire/fw-device.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005-2006 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __fw_device_h +#define __fw_device_h + +#include <linux/fs.h> +#include <linux/cdev.h> +#include <asm/atomic.h> + +enum fw_device_state { + FW_DEVICE_INITIALIZING, + FW_DEVICE_RUNNING, + FW_DEVICE_SHUTDOWN, +}; + +struct fw_attribute_group { + struct attribute_group *groups[2]; + struct attribute_group group; + struct attribute *attrs[11]; +}; + +struct fw_device { + atomic_t state; + struct fw_node *node; + int node_id; + int generation; + struct fw_card *card; + struct device device; + struct list_head link; + struct list_head client_list; + u32 *config_rom; + size_t config_rom_length; + int config_rom_retries; + struct delayed_work work; + struct fw_attribute_group attribute_group; +}; + +static inline struct fw_device * +fw_device(struct device *dev) +{ + return container_of(dev, struct fw_device, device); +} + +static inline int +fw_device_is_shutdown(struct fw_device *device) +{ + return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN; +} + +struct fw_device *fw_device_get(struct fw_device *device); +void fw_device_put(struct fw_device *device); +int fw_device_enable_phys_dma(struct fw_device *device); + +void fw_device_cdev_update(struct fw_device *device); +void fw_device_cdev_remove(struct fw_device *device); + +struct fw_device *fw_device_from_devt(dev_t devt); +extern int fw_cdev_major; + +struct fw_unit { + struct device device; + u32 *directory; + struct fw_attribute_group attribute_group; +}; + +static inline struct fw_unit * +fw_unit(struct device *dev) +{ + return container_of(dev, struct fw_unit, device); +} + +#define CSR_OFFSET 0x40 +#define CSR_LEAF 0x80 +#define CSR_DIRECTORY 0xc0 + +#define CSR_DESCRIPTOR 0x01 +#define CSR_VENDOR 0x03 +#define CSR_HARDWARE_VERSION 0x04 +#define CSR_NODE_CAPABILITIES 0x0c +#define CSR_UNIT 0x11 +#define CSR_SPECIFIER_ID 0x12 +#define CSR_VERSION 0x13 +#define CSR_DEPENDENT_INFO 0x14 +#define CSR_MODEL 0x17 +#define CSR_INSTANCE 0x18 + +#define SBP2_COMMAND_SET_SPECIFIER 0x38 +#define SBP2_COMMAND_SET 0x39 +#define SBP2_COMMAND_SET_REVISION 0x3b +#define SBP2_FIRMWARE_REVISION 0x3c + +struct fw_csr_iterator { + u32 *p; + u32 *end; +}; + +void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p); +int fw_csr_iterator_next(struct fw_csr_iterator *ci, + int *key, int *value); + +#define FW_MATCH_VENDOR 0x0001 +#define FW_MATCH_MODEL 0x0002 +#define FW_MATCH_SPECIFIER_ID 0x0004 +#define FW_MATCH_VERSION 0x0008 + +struct fw_device_id { + u32 match_flags; + u32 vendor; + u32 model; + u32 specifier_id; + u32 version; + void *driver_data; +}; + +struct fw_driver { + struct device_driver driver; + /* Called when the parent device sits through a bus reset. */ + void (*update) (struct fw_unit *unit); + const struct fw_device_id *id_table; +}; + +static inline struct fw_driver * +fw_driver(struct device_driver *drv) +{ + return container_of(drv, struct fw_driver, driver); +} + +extern const struct file_operations fw_device_ops; + +#endif /* __fw_device_h */ diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c new file mode 100644 index 000000000000..2b640e9be6de --- /dev/null +++ b/drivers/firewire/fw-iso.c @@ -0,0 +1,163 @@ +/* + * Isochronous IO functionality + * + * Copyright (C) 2006 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/dma-mapping.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> + +#include "fw-transaction.h" +#include "fw-topology.h" +#include "fw-device.h" + +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; + dma_addr_t address; + + buffer->page_count = page_count; + buffer->direction = direction; + + buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]), + GFP_KERNEL); + if (buffer->pages == NULL) + goto out; + + for (i = 0; i < buffer->page_count; i++) { + buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); + if (buffer->pages[i] == NULL) + goto out_pages; + + address = dma_map_page(card->device, buffer->pages[i], + 0, PAGE_SIZE, direction); + if (dma_mapping_error(address)) { + __free_page(buffer->pages[i]); + goto out_pages; + } + set_page_private(buffer->pages[i], address); + } + + return 0; + + out_pages: + for (j = 0; j < i; j++) { + address = page_private(buffer->pages[j]); + dma_unmap_page(card->device, address, + PAGE_SIZE, DMA_TO_DEVICE); + __free_page(buffer->pages[j]); + } + kfree(buffer->pages); + out: + buffer->pages = NULL; + return retval; +} + +int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma) +{ + unsigned long uaddr; + int i, retval; + + 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; + uaddr += PAGE_SIZE; + } + + return 0; +} + +void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, + struct fw_card *card) +{ + int i; + dma_addr_t address; + + for (i = 0; i < buffer->page_count; i++) { + address = page_private(buffer->pages[i]); + dma_unmap_page(card->device, address, + PAGE_SIZE, DMA_TO_DEVICE); + __free_page(buffer->pages[i]); + } + + kfree(buffer->pages); + 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 *ctx; + + ctx = card->driver->allocate_iso_context(card, type, header_size); + if (IS_ERR(ctx)) + return ctx; + + ctx->card = card; + ctx->type = type; + ctx->channel = channel; + ctx->speed = speed; + ctx->header_size = header_size; + ctx->callback = callback; + ctx->callback_data = callback_data; + + return ctx; +} +EXPORT_SYMBOL(fw_iso_context_create); + +void fw_iso_context_destroy(struct fw_iso_context *ctx) +{ + struct fw_card *card = ctx->card; + + card->driver->free_iso_context(ctx); +} +EXPORT_SYMBOL(fw_iso_context_destroy); + +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); +} +EXPORT_SYMBOL(fw_iso_context_start); + +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); +} +EXPORT_SYMBOL(fw_iso_context_queue); + +int +fw_iso_context_stop(struct fw_iso_context *ctx) +{ + return ctx->card->driver->stop_iso(ctx); +} +EXPORT_SYMBOL(fw_iso_context_stop); diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c new file mode 100644 index 000000000000..1f5c70461b8b --- /dev/null +++ b/drivers/firewire/fw-ohci.c @@ -0,0 +1,1943 @@ +/* + * Driver for OHCI 1394 controllers + * + * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/poll.h> +#include <linux/dma-mapping.h> + +#include <asm/uaccess.h> +#include <asm/semaphore.h> + +#include "fw-transaction.h" +#include "fw-ohci.h" + +#define DESCRIPTOR_OUTPUT_MORE 0 +#define DESCRIPTOR_OUTPUT_LAST (1 << 12) +#define DESCRIPTOR_INPUT_MORE (2 << 12) +#define DESCRIPTOR_INPUT_LAST (3 << 12) +#define DESCRIPTOR_STATUS (1 << 11) +#define DESCRIPTOR_KEY_IMMEDIATE (2 << 8) +#define DESCRIPTOR_PING (1 << 7) +#define DESCRIPTOR_YY (1 << 6) +#define DESCRIPTOR_NO_IRQ (0 << 4) +#define DESCRIPTOR_IRQ_ERROR (1 << 4) +#define DESCRIPTOR_IRQ_ALWAYS (3 << 4) +#define DESCRIPTOR_BRANCH_ALWAYS (3 << 2) +#define DESCRIPTOR_WAIT (3 << 0) + +struct descriptor { + __le16 req_count; + __le16 control; + __le32 data_address; + __le32 branch_address; + __le16 res_count; + __le16 transfer_status; +} __attribute__((aligned(16))); + +struct db_descriptor { + __le16 first_size; + __le16 control; + __le16 second_req_count; + __le16 first_req_count; + __le32 branch_address; + __le16 second_res_count; + __le16 first_res_count; + __le32 reserved0; + __le32 first_buffer; + __le32 second_buffer; + __le32 reserved1; +} __attribute__((aligned(16))); + +#define CONTROL_SET(regs) (regs) +#define CONTROL_CLEAR(regs) ((regs) + 4) +#define COMMAND_PTR(regs) ((regs) + 12) +#define CONTEXT_MATCH(regs) ((regs) + 16) + +struct ar_buffer { + struct descriptor descriptor; + struct ar_buffer *next; + __le32 data[0]; +}; + +struct ar_context { + struct fw_ohci *ohci; + struct ar_buffer *current_buffer; + struct ar_buffer *last_buffer; + void *pointer; + u32 regs; + struct tasklet_struct tasklet; +}; + +struct context; + +typedef int (*descriptor_callback_t)(struct context *ctx, + struct descriptor *d, + struct descriptor *last); +struct context { + struct fw_ohci *ohci; + u32 regs; + + struct descriptor *buffer; + dma_addr_t buffer_bus; + size_t buffer_size; + struct descriptor *head_descriptor; + struct descriptor *tail_descriptor; + struct descriptor *tail_descriptor_last; + struct descriptor *prev_descriptor; + + descriptor_callback_t callback; + + struct tasklet_struct tasklet; +}; + +#define IT_HEADER_SY(v) ((v) << 0) +#define IT_HEADER_TCODE(v) ((v) << 4) +#define IT_HEADER_CHANNEL(v) ((v) << 8) +#define IT_HEADER_TAG(v) ((v) << 14) +#define IT_HEADER_SPEED(v) ((v) << 16) +#define IT_HEADER_DATA_LENGTH(v) ((v) << 16) + +struct iso_context { + struct fw_iso_context base; + struct context context; + void *header; + size_t header_length; +}; + +#define CONFIG_ROM_SIZE 1024 + +struct fw_ohci { + struct fw_card card; + + u32 version; + __iomem char *registers; + dma_addr_t self_id_bus; + __le32 *self_id_cpu; + struct tasklet_struct bus_reset_tasklet; + int node_id; + int generation; + int request_generation; + u32 bus_seconds; + + /* + * Spinlock for accessing fw_ohci data. Never call out of + * this driver with this lock held. + */ + spinlock_t lock; + u32 self_id_buffer[512]; + + /* Config rom buffers */ + __be32 *config_rom; + dma_addr_t config_rom_bus; + __be32 *next_config_rom; + dma_addr_t next_config_rom_bus; + u32 next_header; + + struct ar_context ar_request_ctx; + struct ar_context ar_response_ctx; + struct context at_request_ctx; + struct context at_response_ctx; + + u32 it_context_mask; + struct iso_context *it_context_list; + u32 ir_context_mask; + struct iso_context *ir_context_list; +}; + +static inline struct fw_ohci *fw_ohci(struct fw_card *card) +{ + return container_of(card, struct fw_ohci, card); +} + +#define IT_CONTEXT_CYCLE_MATCH_ENABLE 0x80000000 +#define IR_CONTEXT_BUFFER_FILL 0x80000000 +#define IR_CONTEXT_ISOCH_HEADER 0x40000000 +#define IR_CONTEXT_CYCLE_MATCH_ENABLE 0x20000000 +#define IR_CONTEXT_MULTI_CHANNEL_MODE 0x10000000 +#define IR_CONTEXT_DUAL_BUFFER_MODE 0x08000000 + +#define CONTEXT_RUN 0x8000 +#define CONTEXT_WAKE 0x1000 +#define CONTEXT_DEAD 0x0800 +#define CONTEXT_ACTIVE 0x0400 + +#define OHCI1394_MAX_AT_REQ_RETRIES 0x2 +#define OHCI1394_MAX_AT_RESP_RETRIES 0x2 +#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 + +#define FW_OHCI_MAJOR 240 +#define OHCI1394_REGISTER_SIZE 0x800 +#define OHCI_LOOP_COUNT 500 +#define OHCI1394_PCI_HCI_Control 0x40 +#define SELF_ID_BUF_SIZE 0x800 +#define OHCI_TCODE_PHY_PACKET 0x0e +#define OHCI_VERSION_1_1 0x010010 +#define ISO_BUFFER_SIZE (64 * 1024) +#define AT_BUFFER_SIZE 4096 + +static char ohci_driver_name[] = KBUILD_MODNAME; + +static inline void reg_write(const struct fw_ohci *ohci, int offset, u32 data) +{ + writel(data, ohci->registers + offset); +} + +static inline u32 reg_read(const struct fw_ohci *ohci, int offset) +{ + return readl(ohci->registers + offset); +} + +static inline void flush_writes(const struct fw_ohci *ohci) +{ + /* Do a dummy read to flush writes. */ + reg_read(ohci, OHCI1394_Version); +} + +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; + + reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr)); + msleep(2); + val = reg_read(ohci, OHCI1394_PhyControl); + if ((val & OHCI1394_PhyControl_ReadDone) == 0) { + fw_error("failed to set phy reg bits.\n"); + return -EBUSY; + } + + old = OHCI1394_PhyControl_ReadData(val); + old = (old & ~clear_bits) | set_bits; + reg_write(ohci, OHCI1394_PhyControl, + OHCI1394_PhyControl_Write(addr, old)); + + return 0; +} + +static int ar_context_add_page(struct ar_context *ctx) +{ + struct device *dev = ctx->ohci->card.device; + struct ar_buffer *ab; + dma_addr_t ab_bus; + size_t offset; + + ab = (struct ar_buffer *) __get_free_page(GFP_ATOMIC); + if (ab == NULL) + return -ENOMEM; + + ab_bus = dma_map_single(dev, ab, PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(ab_bus)) { + free_page((unsigned long) ab); + return -ENOMEM; + } + + memset(&ab->descriptor, 0, sizeof(ab->descriptor)); + ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | + DESCRIPTOR_STATUS | + DESCRIPTOR_BRANCH_ALWAYS); + offset = offsetof(struct ar_buffer, data); + ab->descriptor.req_count = cpu_to_le16(PAGE_SIZE - offset); + ab->descriptor.data_address = cpu_to_le32(ab_bus + offset); + ab->descriptor.res_count = cpu_to_le16(PAGE_SIZE - offset); + ab->descriptor.branch_address = 0; + + dma_sync_single_for_device(dev, ab_bus, PAGE_SIZE, DMA_BIDIRECTIONAL); + + ctx->last_buffer->descriptor.branch_address = ab_bus | 1; + ctx->last_buffer->next = ab; + ctx->last_buffer = ab; + + reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); + flush_writes(ctx->ohci); + + return 0; +} + +static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) +{ + struct fw_ohci *ohci = ctx->ohci; + struct fw_packet p; + u32 status, length, tcode; + + p.header[0] = le32_to_cpu(buffer[0]); + p.header[1] = le32_to_cpu(buffer[1]); + p.header[2] = le32_to_cpu(buffer[2]); + + tcode = (p.header[0] >> 4) & 0x0f; + switch (tcode) { + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_READ_QUADLET_RESPONSE: + p.header[3] = (__force __u32) buffer[3]; + p.header_length = 16; + p.payload_length = 0; + break; + + case TCODE_READ_BLOCK_REQUEST : + p.header[3] = le32_to_cpu(buffer[3]); + p.header_length = 16; + p.payload_length = 0; + break; + + case TCODE_WRITE_BLOCK_REQUEST: + case TCODE_READ_BLOCK_RESPONSE: + case TCODE_LOCK_REQUEST: + case TCODE_LOCK_RESPONSE: + p.header[3] = le32_to_cpu(buffer[3]); + p.header_length = 16; + p.payload_length = p.header[3] >> 16; + break; + + case TCODE_WRITE_RESPONSE: + case TCODE_READ_QUADLET_REQUEST: + case OHCI_TCODE_PHY_PACKET: + p.header_length = 12; + p.payload_length = 0; + break; + } + + p.payload = (void *) buffer + p.header_length; + + /* FIXME: What to do about evt_* errors? */ + length = (p.header_length + p.payload_length + 3) / 4; + status = le32_to_cpu(buffer[length]); + + p.ack = ((status >> 16) & 0x1f) - 16; + p.speed = (status >> 21) & 0x7; + p.timestamp = status & 0xffff; + p.generation = ohci->request_generation; + + /* + * The OHCI bus reset handler synthesizes a phy packet with + * the new generation number when a bus reset happens (see + * section 8.4.2.3). This helps us determine when a request + * was received and make sure we send the response in the same + * generation. We only need this for requests; for responses + * we use the unique tlabel for finding the matching + * request. + */ + + if (p.ack + 16 == 0x09) + ohci->request_generation = (buffer[2] >> 16) & 0xff; + else if (ctx == &ohci->ar_request_ctx) + fw_core_handle_request(&ohci->card, &p); + else + fw_core_handle_response(&ohci->card, &p); + + return buffer + length + 1; +} + +static void ar_context_tasklet(unsigned long data) +{ + struct ar_context *ctx = (struct ar_context *)data; + struct fw_ohci *ohci = ctx->ohci; + struct ar_buffer *ab; + struct descriptor *d; + void *buffer, *end; + + ab = ctx->current_buffer; + d = &ab->descriptor; + + if (d->res_count == 0) { + size_t size, rest, offset; + + /* + * This descriptor is finished and we may have a + * packet split across this and the next buffer. We + * reuse the page for reassembling the split packet. + */ + + offset = offsetof(struct ar_buffer, data); + dma_unmap_single(ohci->card.device, + ab->descriptor.data_address - offset, + PAGE_SIZE, DMA_BIDIRECTIONAL); + + buffer = ab; + ab = ab->next; + d = &ab->descriptor; + size = buffer + PAGE_SIZE - ctx->pointer; + rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); + memmove(buffer, ctx->pointer, size); + memcpy(buffer + size, ab->data, rest); + ctx->current_buffer = ab; + ctx->pointer = (void *) ab->data + rest; + end = buffer + size + rest; + + while (buffer < end) + buffer = handle_ar_packet(ctx, buffer); + + free_page((unsigned long)buffer); + ar_context_add_page(ctx); + } else { + buffer = ctx->pointer; + ctx->pointer = end = + (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count); + + while (buffer < end) + buffer = handle_ar_packet(ctx, buffer); + } +} + +static int +ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, u32 regs) +{ + struct ar_buffer ab; + + ctx->regs = regs; + ctx->ohci = ohci; + ctx->last_buffer = &ab; + tasklet_init(&ctx->tasklet, ar_context_tasklet, (unsigned long)ctx); + + ar_context_add_page(ctx); + ar_context_add_page(ctx); + ctx->current_buffer = ab.next; + ctx->pointer = ctx->current_buffer->data; + + reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ab.descriptor.branch_address); + reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN); + flush_writes(ctx->ohci); + + return 0; +} + +static void context_tasklet(unsigned long data) +{ + struct context *ctx = (struct context *) data; + struct fw_ohci *ohci = ctx->ohci; + struct descriptor *d, *last; + u32 address; + int z; + + dma_sync_single_for_cpu(ohci->card.device, ctx->buffer_bus, + ctx->buffer_size, DMA_TO_DEVICE); + + d = ctx->tail_descriptor; + last = ctx->tail_descriptor_last; + + while (last->branch_address != 0) { + address = le32_to_cpu(last->branch_address); + z = address & 0xf; + d = ctx->buffer + (address - ctx->buffer_bus) / sizeof(*d); + last = (z == 2) ? d : d + z - 1; + + if (!ctx->callback(ctx, d, last)) + break; + + ctx->tail_descriptor = d; + ctx->tail_descriptor_last = last; + } +} + +static int +context_init(struct context *ctx, struct fw_ohci *ohci, + size_t buffer_size, u32 regs, + descriptor_callback_t callback) +{ + ctx->ohci = ohci; + ctx->regs = regs; + ctx->buffer_size = buffer_size; + ctx->buffer = kmalloc(buffer_size, GFP_KERNEL); + if (ctx->buffer == NULL) + return -ENOMEM; + + tasklet_init(&ctx->tasklet, context_tasklet, (unsigned long)ctx); + ctx->callback = callback; + + ctx->buffer_bus = + dma_map_single(ohci->card.device, ctx->buffer, + buffer_size, DMA_TO_DEVICE); + if (dma_mapping_error(ctx->buffer_bus)) { + kfree(ctx->buffer); + return -ENOMEM; + } + + ctx->head_descriptor = ctx->buffer; + ctx->prev_descriptor = ctx->buffer; + ctx->tail_descriptor = ctx->buffer; + ctx->tail_descriptor_last = ctx->buffer; + + /* + * We put a dummy descriptor in the buffer that has a NULL + * branch address and looks like it's been sent. That way we + * have a descriptor to append DMA programs to. Also, the + * ring buffer invariant is that it always has at least one + * element so that head == tail means buffer full. + */ + + memset(ctx->head_descriptor, 0, sizeof(*ctx->head_descriptor)); + ctx->head_descriptor->control = cpu_to_le16(DESCRIPTOR_OUTPUT_LAST); + ctx->head_descriptor->transfer_status = cpu_to_le16(0x8011); + ctx->head_descriptor++; + + return 0; +} + +static void +context_release(struct context *ctx) +{ + struct fw_card *card = &ctx->ohci->card; + + dma_unmap_single(card->device, ctx->buffer_bus, + ctx->buffer_size, DMA_TO_DEVICE); + kfree(ctx->buffer); +} + +static struct descriptor * +context_get_descriptors(struct context *ctx, int z, dma_addr_t *d_bus) +{ + struct descriptor *d, *tail, *end; + + d = ctx->head_descriptor; + tail = ctx->tail_descriptor; + end = ctx->buffer + ctx->buffer_size / sizeof(*d); + + if (d + z <= tail) { + goto has_space; + } else if (d > tail && d + z <= end) { + goto has_space; + } else if (d > tail && ctx->buffer + z <= tail) { + d = ctx->buffer; + goto has_space; + } + + return NULL; + + has_space: + memset(d, 0, z * sizeof(*d)); + *d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d); + + return d; +} + +static void context_run(struct context *ctx, u32 extra) +{ + struct fw_ohci *ohci = ctx->ohci; + + reg_write(ohci, COMMAND_PTR(ctx->regs), + le32_to_cpu(ctx->tail_descriptor_last->branch_address)); + reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0); + reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra); + flush_writes(ohci); +} + +static void context_append(struct context *ctx, + struct descriptor *d, int z, int extra) +{ + dma_addr_t d_bus; + + d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d); + + ctx->head_descriptor = d + z + extra; + ctx->prev_descriptor->branch_address = cpu_to_le32(d_bus | z); + ctx->prev_descriptor = z == 2 ? d : d + z - 1; + + dma_sync_single_for_device(ctx->ohci->card.device, ctx->buffer_bus, + ctx->buffer_size, DMA_TO_DEVICE); + + reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); + flush_writes(ctx->ohci); +} + +static void context_stop(struct context *ctx) +{ + u32 reg; + int i; + + reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); + flush_writes(ctx->ohci); + + for (i = 0; i < 10; i++) { + reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs)); + if ((reg & CONTEXT_ACTIVE) == 0) + break; + + fw_notify("context_stop: still active (0x%08x)\n", reg); + msleep(1); + } +} + +struct driver_data { + struct fw_packet *packet; +}; + +/* + * This function apppends a packet to the DMA queue for transmission. + * 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) +{ + struct fw_ohci *ohci = ctx->ohci; + dma_addr_t d_bus, payload_bus; + struct driver_data *driver_data; + struct descriptor *d, *last; + __le32 *header; + int z, tcode; + u32 reg; + + d = context_get_descriptors(ctx, 4, &d_bus); + if (d == NULL) { + packet->ack = RCODE_SEND_ERROR; + return -1; + } + + d[0].control = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE); + d[0].res_count = cpu_to_le16(packet->timestamp); + + /* + * The DMA format for asyncronous link packets is different + * from the IEEE1394 layout, so shift the fields around + * accordingly. If header_length is 8, it's a PHY packet, to + * which we need to prepend an extra quadlet. + */ + + header = (__le32 *) &d[1]; + if (packet->header_length > 8) { + header[0] = cpu_to_le32((packet->header[0] & 0xffff) | + (packet->speed << 16)); + header[1] = cpu_to_le32((packet->header[1] & 0xffff) | + (packet->header[0] & 0xffff0000)); + header[2] = cpu_to_le32(packet->header[2]); + + tcode = (packet->header[0] >> 4) & 0x0f; + if (TCODE_IS_BLOCK_PACKET(tcode)) + header[3] = cpu_to_le32(packet->header[3]); + else + header[3] = (__force __le32) packet->header[3]; + + d[0].req_count = cpu_to_le16(packet->header_length); + } else { + 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); + } + + driver_data = (struct driver_data *) &d[3]; + driver_data->packet = packet; + packet->driver_data = driver_data; + + if (packet->payload_length > 0) { + payload_bus = + dma_map_single(ohci->card.device, packet->payload, + packet->payload_length, DMA_TO_DEVICE); + if (dma_mapping_error(payload_bus)) { + packet->ack = RCODE_SEND_ERROR; + return -1; + } + + d[2].req_count = cpu_to_le16(packet->payload_length); + d[2].data_address = cpu_to_le32(payload_bus); + last = &d[2]; + z = 3; + } else { + last = &d[0]; + z = 2; + } + + last->control |= cpu_to_le16(DESCRIPTOR_OUTPUT_LAST | + DESCRIPTOR_IRQ_ALWAYS | + DESCRIPTOR_BRANCH_ALWAYS); + + /* FIXME: Document how the locking works. */ + if (ohci->generation != packet->generation) { + packet->ack = RCODE_GENERATION; + return -1; + } + + context_append(ctx, d, z, 4 - z); + + /* If the context isn't already running, start it up. */ + reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs)); + if ((reg & CONTEXT_RUN) == 0) + context_run(ctx, 0); + + return 0; +} + +static int handle_at_packet(struct context *context, + struct descriptor *d, + struct descriptor *last) +{ + struct driver_data *driver_data; + struct fw_packet *packet; + struct fw_ohci *ohci = context->ohci; + dma_addr_t payload_bus; + int evt; + + if (last->transfer_status == 0) + /* This descriptor isn't done yet, stop iteration. */ + return 0; + + driver_data = (struct driver_data *) &d[3]; + packet = driver_data->packet; + if (packet == NULL) + /* This packet was cancelled, just continue. */ + return 1; + + payload_bus = le32_to_cpu(last->data_address); + if (payload_bus != 0) + dma_unmap_single(ohci->card.device, payload_bus, + packet->payload_length, DMA_TO_DEVICE); + + evt = le16_to_cpu(last->transfer_status) & 0x1f; + packet->timestamp = le16_to_cpu(last->res_count); + + switch (evt) { + case OHCI1394_evt_timeout: + /* Async response transmit timed out. */ + packet->ack = RCODE_CANCELLED; + break; + + case OHCI1394_evt_flushed: + /* + * The packet was flushed should give same error as + * when we try to use a stale generation count. + */ + packet->ack = RCODE_GENERATION; + break; + + case OHCI1394_evt_missing_ack: + /* + * Using a valid (current) generation count, but the + * node is not on the bus or not sending acks. + */ + packet->ack = RCODE_NO_ACK; + break; + + case ACK_COMPLETE + 0x10: + case ACK_PENDING + 0x10: + case ACK_BUSY_X + 0x10: + case ACK_BUSY_A + 0x10: + case ACK_BUSY_B + 0x10: + case ACK_DATA_ERROR + 0x10: + case ACK_TYPE_ERROR + 0x10: + packet->ack = evt - 0x10; + break; + + default: + packet->ack = RCODE_SEND_ERROR; + break; + } + + packet->callback(packet, &ohci->card, packet->ack); + + return 1; +} + +#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff) +#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f) +#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff) +#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) +{ + struct fw_packet response; + int tcode, length, i; + + tcode = HEADER_GET_TCODE(packet->header[0]); + if (TCODE_IS_BLOCK_PACKET(tcode)) + length = HEADER_GET_DATA_LENGTH(packet->header[3]); + else + length = 4; + + i = csr - CSR_CONFIG_ROM; + if (i + length > CONFIG_ROM_SIZE) { + fw_fill_response(&response, packet->header, + RCODE_ADDRESS_ERROR, NULL, 0); + } else if (!TCODE_IS_READ_REQUEST(tcode)) { + fw_fill_response(&response, packet->header, + RCODE_TYPE_ERROR, NULL, 0); + } else { + fw_fill_response(&response, packet->header, RCODE_COMPLETE, + (void *) ohci->config_rom + i, length); + } + + fw_core_handle_response(&ohci->card, &response); +} + +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; + __be32 *payload, lock_old; + u32 lock_arg, lock_data; + + tcode = HEADER_GET_TCODE(packet->header[0]); + length = HEADER_GET_DATA_LENGTH(packet->header[3]); + payload = packet->payload; + ext_tcode = HEADER_GET_EXTENDED_TCODE(packet->header[3]); + + if (tcode == TCODE_LOCK_REQUEST && + ext_tcode == EXTCODE_COMPARE_SWAP && length == 8) { + lock_arg = be32_to_cpu(payload[0]); + lock_data = be32_to_cpu(payload[1]); + } else if (tcode == TCODE_READ_QUADLET_REQUEST) { + lock_arg = 0; + lock_data = 0; + } else { + fw_fill_response(&response, packet->header, + RCODE_TYPE_ERROR, NULL, 0); + goto out; + } + + sel = (csr - CSR_BUS_MANAGER_ID) / 4; + reg_write(ohci, OHCI1394_CSRData, lock_data); + reg_write(ohci, OHCI1394_CSRCompareData, lock_arg); + reg_write(ohci, OHCI1394_CSRControl, sel); + + if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) + lock_old = cpu_to_be32(reg_read(ohci, OHCI1394_CSRData)); + else + fw_notify("swap not done yet\n"); + + fw_fill_response(&response, packet->header, + RCODE_COMPLETE, &lock_old, sizeof(lock_old)); + out: + fw_core_handle_response(&ohci->card, &response); +} + +static void +handle_local_request(struct context *ctx, struct fw_packet *packet) +{ + u64 offset; + u32 csr; + + if (ctx == &ctx->ohci->at_request_ctx) { + packet->ack = ACK_PENDING; + packet->callback(packet, &ctx->ohci->card, packet->ack); + } + + offset = + ((unsigned long long) + HEADER_GET_OFFSET_HIGH(packet->header[1]) << 32) | + packet->header[2]; + csr = offset - CSR_REGISTER_BASE; + + /* Handle config rom reads. */ + if (csr >= CSR_CONFIG_ROM && csr < CSR_CONFIG_ROM_END) + handle_local_rom(ctx->ohci, packet, csr); + else switch (csr) { + case CSR_BUS_MANAGER_ID: + case CSR_BANDWIDTH_AVAILABLE: + case CSR_CHANNELS_AVAILABLE_HI: + case CSR_CHANNELS_AVAILABLE_LO: + handle_local_lock(ctx->ohci, packet, csr); + break; + default: + if (ctx == &ctx->ohci->at_request_ctx) + fw_core_handle_request(&ctx->ohci->card, packet); + else + fw_core_handle_response(&ctx->ohci->card, packet); + break; + } + + if (ctx == &ctx->ohci->at_response_ctx) { + packet->ack = ACK_COMPLETE; + packet->callback(packet, &ctx->ohci->card, packet->ack); + } +} + +static void +at_context_transmit(struct context *ctx, struct fw_packet *packet) +{ + unsigned long flags; + int retval; + + spin_lock_irqsave(&ctx->ohci->lock, flags); + + if (HEADER_GET_DESTINATION(packet->header[0]) == ctx->ohci->node_id && + ctx->ohci->generation == packet->generation) { + spin_unlock_irqrestore(&ctx->ohci->lock, flags); + handle_local_request(ctx, packet); + return; + } + + retval = at_context_queue_packet(ctx, packet); + spin_unlock_irqrestore(&ctx->ohci->lock, flags); + + if (retval < 0) + packet->callback(packet, &ctx->ohci->card, packet->ack); + +} + +static void bus_reset_tasklet(unsigned long data) +{ + struct fw_ohci *ohci = (struct fw_ohci *)data; + int self_id_count, i, j, reg; + int generation, new_generation; + unsigned long flags; + + reg = reg_read(ohci, OHCI1394_NodeID); + if (!(reg & OHCI1394_NodeID_idValid)) { + fw_error("node ID not valid, new bus reset in progress\n"); + return; + } + ohci->node_id = reg & 0xffff; + + /* + * The count in the SelfIDCount register is the number of + * bytes in the self ID receive buffer. Since we also receive + * the inverted quadlets and a header quadlet, we shift one + * bit extra to get the actual number of self IDs. + */ + + self_id_count = (reg_read(ohci, OHCI1394_SelfIDCount) >> 3) & 0x3ff; + generation = (le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff; + + for (i = 1, j = 0; j < self_id_count; i += 2, j++) { + if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) + fw_error("inconsistent self IDs\n"); + ohci->self_id_buffer[j] = le32_to_cpu(ohci->self_id_cpu[i]); + } + + /* + * Check the consistency of the self IDs we just read. The + * problem we face is that a new bus reset can start while we + * read out the self IDs from the DMA buffer. If this happens, + * the DMA buffer will be overwritten with new self IDs and we + * will read out inconsistent data. The OHCI specification + * (section 11.2) recommends a technique similar to + * linux/seqlock.h, where we remember the generation of the + * self IDs in the buffer before reading them out and compare + * it to the current generation after reading them out. If + * the two generations match we know we have a consistent set + * of self IDs. + */ + + new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff; + if (new_generation != generation) { + fw_notify("recursive bus reset detected, " + "discarding self ids\n"); + return; + } + + /* FIXME: Document how the locking works. */ + spin_lock_irqsave(&ohci->lock, flags); + + ohci->generation = generation; + context_stop(&ohci->at_request_ctx); + context_stop(&ohci->at_response_ctx); + reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); + + /* + * This next bit is unrelated to the AT context stuff but we + * have to do it under the spinlock also. If a new config rom + * was set up before this reset, the old one is now no longer + * in use and we can free it. Update the config rom pointers + * to point to the current config rom and clear the + * next_config_rom pointer so a new udpate can take place. + */ + + if (ohci->next_config_rom != NULL) { + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + ohci->config_rom, ohci->config_rom_bus); + ohci->config_rom = ohci->next_config_rom; + ohci->config_rom_bus = ohci->next_config_rom_bus; + ohci->next_config_rom = NULL; + + /* + * Restore config_rom image and manually update + * config_rom registers. Writing the header quadlet + * will indicate that the config rom is ready, so we + * do that last. + */ + reg_write(ohci, OHCI1394_BusOptions, + be32_to_cpu(ohci->config_rom[2])); + ohci->config_rom[0] = cpu_to_be32(ohci->next_header); + reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->next_header); + } + + spin_unlock_irqrestore(&ohci->lock, flags); + + fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation, + self_id_count, ohci->self_id_buffer); +} + +static irqreturn_t irq_handler(int irq, void *data) +{ + struct fw_ohci *ohci = data; + u32 event, iso_event, cycle_time; + int i; + + event = reg_read(ohci, OHCI1394_IntEventClear); + + if (!event) + return IRQ_NONE; + + reg_write(ohci, OHCI1394_IntEventClear, event); + + if (event & OHCI1394_selfIDComplete) + tasklet_schedule(&ohci->bus_reset_tasklet); + + if (event & OHCI1394_RQPkt) + tasklet_schedule(&ohci->ar_request_ctx.tasklet); + + if (event & OHCI1394_RSPkt) + tasklet_schedule(&ohci->ar_response_ctx.tasklet); + + if (event & OHCI1394_reqTxComplete) + tasklet_schedule(&ohci->at_request_ctx.tasklet); + + if (event & OHCI1394_respTxComplete) + tasklet_schedule(&ohci->at_response_ctx.tasklet); + + iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event); + + while (iso_event) { + i = ffs(iso_event) - 1; + tasklet_schedule(&ohci->ir_context_list[i].context.tasklet); + iso_event &= ~(1 << i); + } + + iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event); + + while (iso_event) { + i = ffs(iso_event) - 1; + tasklet_schedule(&ohci->it_context_list[i].context.tasklet); + iso_event &= ~(1 << i); + } + + if (event & OHCI1394_cycle64Seconds) { + cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + if ((cycle_time & 0x80000000) == 0) + ohci->bus_seconds++; + } + + return IRQ_HANDLED; +} + +static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length) +{ + struct fw_ohci *ohci = fw_ohci(card); + struct pci_dev *dev = to_pci_dev(card->device); + + /* + * When the link is not yet enabled, the atomic config rom + * update mechanism described below in ohci_set_config_rom() + * is not active. We have to update ConfigRomHeader and + * BusOptions manually, and the write to ConfigROMmap takes + * effect immediately. We tie this to the enabling of the + * link, so we have a valid config rom before enabling - the + * OHCI requires that ConfigROMhdr and BusOptions have valid + * values before enabling. + * + * However, when the ConfigROMmap is written, some controllers + * always read back quadlets 0 and 2 from the config rom to + * the ConfigRomHeader and BusOptions registers on bus reset. + * They shouldn't do that in this initial case where the link + * isn't enabled. This means we have to use the same + * workaround here, setting the bus header to 0 and then write + * the right values in the bus reset tasklet. + */ + + ohci->next_config_rom = + dma_alloc_coherent(ohci->card.device, CONFIG_ROM_SIZE, + &ohci->next_config_rom_bus, GFP_KERNEL); + if (ohci->next_config_rom == NULL) + return -ENOMEM; + + memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE); + fw_memcpy_to_be32(ohci->next_config_rom, config_rom, length * 4); + + ohci->next_header = config_rom[0]; + ohci->next_config_rom[0] = 0; + reg_write(ohci, OHCI1394_ConfigROMhdr, 0); + reg_write(ohci, OHCI1394_BusOptions, config_rom[2]); + reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus); + + reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000); + + if (request_irq(dev->irq, irq_handler, + IRQF_SHARED, ohci_driver_name, ohci)) { + fw_error("Failed to allocate shared interrupt %d.\n", + dev->irq); + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + ohci->config_rom, ohci->config_rom_bus); + return -EIO; + } + + reg_write(ohci, OHCI1394_HCControlSet, + OHCI1394_HCControl_linkEnable | + OHCI1394_HCControl_BIBimageValid); + flush_writes(ohci); + + /* + * We are ready to go, initiate bus reset to finish the + * initialization. + */ + + fw_core_initiate_bus_reset(&ohci->card, 1); + + return 0; +} + +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 = 0; + __be32 *next_config_rom; + dma_addr_t next_config_rom_bus; + + ohci = fw_ohci(card); + + /* + * When the OHCI controller is enabled, the config rom update + * mechanism is a bit tricky, but easy enough to use. See + * section 5.5.6 in the OHCI specification. + * + * The OHCI controller caches the new config rom address in a + * shadow register (ConfigROMmapNext) and needs a bus reset + * for the changes to take place. When the bus reset is + * detected, the controller loads the new values for the + * ConfigRomHeader and BusOptions registers from the specified + * config rom and loads ConfigROMmap from the ConfigROMmapNext + * shadow register. All automatically and atomically. + * + * Now, there's a twist to this story. The automatic load of + * ConfigRomHeader and BusOptions doesn't honor the + * noByteSwapData bit, so with a be32 config rom, the + * controller will load be32 values in to these registers + * during the atomic update, even on litte endian + * architectures. The workaround we use is to put a 0 in the + * header quadlet; 0 is endian agnostic and means that the + * config rom isn't ready yet. In the bus reset tasklet we + * then set up the real values for the two registers. + * + * We use ohci->lock to avoid racing with the code that sets + * ohci->next_config_rom to NULL (see bus_reset_tasklet). + */ + + next_config_rom = + dma_alloc_coherent(ohci->card.device, CONFIG_ROM_SIZE, + &next_config_rom_bus, GFP_KERNEL); + if (next_config_rom == NULL) + return -ENOMEM; + + spin_lock_irqsave(&ohci->lock, flags); + + if (ohci->next_config_rom == NULL) { + ohci->next_config_rom = next_config_rom; + ohci->next_config_rom_bus = next_config_rom_bus; + + memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE); + fw_memcpy_to_be32(ohci->next_config_rom, config_rom, + length * 4); + + ohci->next_header = config_rom[0]; + ohci->next_config_rom[0] = 0; + + reg_write(ohci, OHCI1394_ConfigROMmap, + ohci->next_config_rom_bus); + } else { + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + next_config_rom, next_config_rom_bus); + retval = -EBUSY; + } + + spin_unlock_irqrestore(&ohci->lock, flags); + + /* + * Now initiate a bus reset to have the changes take + * effect. We clean up the old config rom memory and DMA + * mappings in the bus reset tasklet, since the OHCI + * controller could need to access it before the bus reset + * takes effect. + */ + if (retval == 0) + fw_core_initiate_bus_reset(&ohci->card, 1); + + return retval; +} + +static void ohci_send_request(struct fw_card *card, struct fw_packet *packet) +{ + struct fw_ohci *ohci = fw_ohci(card); + + at_context_transmit(&ohci->at_request_ctx, packet); +} + +static void ohci_send_response(struct fw_card *card, struct fw_packet *packet) +{ + struct fw_ohci *ohci = fw_ohci(card); + + at_context_transmit(&ohci->at_response_ctx, packet); +} + +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; + + tasklet_disable(&ctx->tasklet); + + if (packet->ack != 0) + goto out; + + driver_data->packet = NULL; + packet->ack = RCODE_CANCELLED; + packet->callback(packet, &ohci->card, packet->ack); + retval = 0; + + out: + tasklet_enable(&ctx->tasklet); + + return retval; +} + +static int +ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) +{ + struct fw_ohci *ohci = fw_ohci(card); + unsigned long flags; + int n, retval = 0; + + /* + * FIXME: Make sure this bitmask is cleared when we clear the busReset + * interrupt bit. Clear physReqResourceAllBuses on bus reset. + */ + + spin_lock_irqsave(&ohci->lock, flags); + + if (ohci->generation != generation) { + retval = -ESTALE; + goto out; + } + + /* + * Note, if the node ID contains a non-local bus ID, physical DMA is + * enabled for _all_ nodes on remote buses. + */ + + n = (node_id & 0xffc0) == LOCAL_BUS ? node_id & 0x3f : 63; + if (n < 32) + reg_write(ohci, OHCI1394_PhyReqFilterLoSet, 1 << n); + else + reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 1 << (n - 32)); + + flush_writes(ohci); + out: + spin_unlock_irqrestore(&ohci->lock, flags); + return retval; +} + +static u64 +ohci_get_bus_time(struct fw_card *card) +{ + struct fw_ohci *ohci = fw_ohci(card); + u32 cycle_time; + u64 bus_time; + + cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + bus_time = ((u64) ohci->bus_seconds << 32) | cycle_time; + + return bus_time; +} + +static int handle_ir_dualbuffer_packet(struct context *context, + struct descriptor *d, + struct descriptor *last) +{ + struct iso_context *ctx = + container_of(context, struct iso_context, context); + struct db_descriptor *db = (struct db_descriptor *) d; + __le32 *ir_header; + size_t header_length; + void *p, *end; + int i; + + if (db->first_res_count > 0 && db->second_res_count > 0) + /* This descriptor isn't done yet, stop iteration. */ + return 0; + + 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; + p += ctx->base.header_size + 4; + } + + ctx->header_length = i; + + if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) { + ir_header = (__le32 *) (db + 1); + ctx->base.callback(&ctx->base, + le32_to_cpu(ir_header[0]) & 0xffff, + ctx->header_length, ctx->header, + ctx->base.callback_data); + ctx->header_length = 0; + } + + return 1; +} + +static int handle_it_packet(struct context *context, + struct descriptor *d, + struct descriptor *last) +{ + struct iso_context *ctx = + container_of(context, struct iso_context, context); + + if (last->transfer_status == 0) + /* This descriptor isn't done yet, stop iteration. */ + return 0; + + if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) + ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count), + 0, NULL, ctx->base.callback_data); + + return 1; +} + +static struct fw_iso_context * +ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size) +{ + struct fw_ohci *ohci = fw_ohci(card); + struct iso_context *ctx, *list; + descriptor_callback_t callback; + u32 *mask, regs; + unsigned long flags; + int index, retval = -ENOMEM; + + if (type == FW_ISO_CONTEXT_TRANSMIT) { + mask = &ohci->it_context_mask; + list = ohci->it_context_list; + callback = handle_it_packet; + } else { + mask = &ohci->ir_context_mask; + list = ohci->ir_context_list; + callback = handle_ir_dualbuffer_packet; + } + + /* FIXME: We need a fallback for pre 1.1 OHCI. */ + if (callback == handle_ir_dualbuffer_packet && + ohci->version < OHCI_VERSION_1_1) + return ERR_PTR(-EINVAL); + + spin_lock_irqsave(&ohci->lock, flags); + index = ffs(*mask) - 1; + if (index >= 0) + *mask &= ~(1 << index); + spin_unlock_irqrestore(&ohci->lock, flags); + + if (index < 0) + return ERR_PTR(-EBUSY); + + if (type == FW_ISO_CONTEXT_TRANSMIT) + regs = OHCI1394_IsoXmitContextBase(index); + else + regs = OHCI1394_IsoRcvContextBase(index); + + ctx = &list[index]; + memset(ctx, 0, sizeof(*ctx)); + ctx->header_length = 0; + ctx->header = (void *) __get_free_page(GFP_KERNEL); + if (ctx->header == NULL) + goto out; + + retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE, + regs, callback); + if (retval < 0) + goto out_with_header; + + return &ctx->base; + + out_with_header: + free_page((unsigned long)ctx->header); + out: + spin_lock_irqsave(&ohci->lock, flags); + *mask |= 1 << index; + spin_unlock_irqrestore(&ohci->lock, flags); + + return ERR_PTR(retval); +} + +static int ohci_start_iso(struct fw_iso_context *base, + s32 cycle, u32 sync, u32 tags) +{ + struct iso_context *ctx = container_of(base, struct iso_context, base); + struct fw_ohci *ohci = ctx->context.ohci; + u32 control, match; + int index; + + if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { + index = ctx - ohci->it_context_list; + match = 0; + if (cycle >= 0) + match = IT_CONTEXT_CYCLE_MATCH_ENABLE | + (cycle & 0x7fff) << 16; + + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index); + reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index); + context_run(&ctx->context, match); + } else { + index = ctx - ohci->ir_context_list; + control = IR_CONTEXT_DUAL_BUFFER_MODE | IR_CONTEXT_ISOCH_HEADER; + match = (tags << 28) | (sync << 8) | ctx->base.channel; + if (cycle >= 0) { + match |= (cycle & 0x07fff) << 12; + control |= IR_CONTEXT_CYCLE_MATCH_ENABLE; + } + + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 1 << index); + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); + reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match); + context_run(&ctx->context, control); + } + + return 0; +} + +static int ohci_stop_iso(struct fw_iso_context *base) +{ + struct fw_ohci *ohci = fw_ohci(base->card); + struct iso_context *ctx = container_of(base, struct iso_context, base); + int index; + + if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { + index = ctx - ohci->it_context_list; + reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index); + } else { + index = ctx - ohci->ir_context_list; + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index); + } + flush_writes(ohci); + context_stop(&ctx->context); + + return 0; +} + +static void ohci_free_iso_context(struct fw_iso_context *base) +{ + struct fw_ohci *ohci = fw_ohci(base->card); + struct iso_context *ctx = container_of(base, struct iso_context, base); + unsigned long flags; + int index; + + ohci_stop_iso(base); + context_release(&ctx->context); + free_page((unsigned long)ctx->header); + + spin_lock_irqsave(&ohci->lock, flags); + + if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { + index = ctx - ohci->it_context_list; + ohci->it_context_mask |= 1 << index; + } else { + index = ctx - ohci->ir_context_list; + ohci->ir_context_mask |= 1 << index; + } + + 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) +{ + struct iso_context *ctx = container_of(base, struct iso_context, base); + struct descriptor *d, *last, *pd; + struct fw_iso_packet *p; + __le32 *header; + dma_addr_t d_bus, page_bus; + u32 z, header_z, payload_z, irq; + u32 payload_index, payload_end_index, next_page_index; + int page, end_page, i, length, offset; + + /* + * FIXME: Cycle lost behavior should be configurable: lose + * packet, retransmit or terminate.. + */ + + p = packet; + payload_index = payload; + + if (p->skip) + z = 1; + else + z = 2; + if (p->header_length > 0) + z++; + + /* Determine the first page the payload isn't contained in. */ + end_page = PAGE_ALIGN(payload_index + p->payload_length) >> PAGE_SHIFT; + if (p->payload_length > 0) + payload_z = end_page - (payload_index >> PAGE_SHIFT); + else + payload_z = 0; + + z += payload_z; + + /* Get header size in number of descriptors. */ + header_z = DIV_ROUND_UP(p->header_length, sizeof(*d)); + + d = context_get_descriptors(&ctx->context, z + header_z, &d_bus); + if (d == NULL) + return -ENOMEM; + + if (!p->skip) { + d[0].control = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE); + d[0].req_count = cpu_to_le16(8); + + header = (__le32 *) &d[1]; + header[0] = cpu_to_le32(IT_HEADER_SY(p->sy) | + IT_HEADER_TAG(p->tag) | + IT_HEADER_TCODE(TCODE_STREAM_DATA) | + IT_HEADER_CHANNEL(ctx->base.channel) | + IT_HEADER_SPEED(ctx->base.speed)); + header[1] = + cpu_to_le32(IT_HEADER_DATA_LENGTH(p->header_length + + p->payload_length)); + } + + if (p->header_length > 0) { + d[2].req_count = cpu_to_le16(p->header_length); + d[2].data_address = cpu_to_le32(d_bus + z * sizeof(*d)); + memcpy(&d[z], p->header, p->header_length); + } + + pd = d + z - payload_z; + payload_end_index = payload_index + p->payload_length; + for (i = 0; i < payload_z; i++) { + page = payload_index >> PAGE_SHIFT; + offset = payload_index & ~PAGE_MASK; + next_page_index = (page + 1) << PAGE_SHIFT; + length = + min(next_page_index, payload_end_index) - payload_index; + pd[i].req_count = cpu_to_le16(length); + + page_bus = page_private(buffer->pages[page]); + pd[i].data_address = cpu_to_le32(page_bus + offset); + + payload_index += length; + } + + if (p->interrupt) + irq = DESCRIPTOR_IRQ_ALWAYS; + else + irq = DESCRIPTOR_NO_IRQ; + + last = z == 2 ? d : d + z - 1; + last->control |= cpu_to_le16(DESCRIPTOR_OUTPUT_LAST | + DESCRIPTOR_STATUS | + DESCRIPTOR_BRANCH_ALWAYS | + irq); + + context_append(&ctx->context, d, z, header_z); + + 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) +{ + struct iso_context *ctx = container_of(base, struct iso_context, base); + struct db_descriptor *db = NULL; + struct descriptor *d; + struct fw_iso_packet *p; + dma_addr_t d_bus, page_bus; + u32 z, header_z, length, rest; + int page, offset, packet_count, header_size; + + /* + * FIXME: Cycle lost behavior should be configurable: lose + * packet, retransmit or terminate.. + */ + + if (packet->skip) { + d = context_get_descriptors(&ctx->context, 2, &d_bus); + if (d == NULL) + return -ENOMEM; + + db = (struct db_descriptor *) d; + db->control = cpu_to_le16(DESCRIPTOR_STATUS | + DESCRIPTOR_BRANCH_ALWAYS | + DESCRIPTOR_WAIT); + db->first_size = cpu_to_le16(ctx->base.header_size + 4); + context_append(&ctx->context, d, 2, 0); + } + + p = packet; + z = 2; + + /* + * The OHCI controller puts the status word in the header + * buffer too, so we need 4 extra bytes per packet. + */ + packet_count = p->header_length / ctx->base.header_size; + header_size = packet_count * (ctx->base.header_size + 4); + + /* Get header size in number of descriptors. */ + header_z = DIV_ROUND_UP(header_size, sizeof(*d)); + page = payload >> PAGE_SHIFT; + offset = payload & ~PAGE_MASK; + rest = p->payload_length; + + /* FIXME: OHCI 1.0 doesn't support dual buffer receive */ + /* FIXME: make packet-per-buffer/dual-buffer a context option */ + while (rest > 0) { + d = context_get_descriptors(&ctx->context, + z + header_z, &d_bus); + if (d == NULL) + return -ENOMEM; + + 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_req_count = cpu_to_le16(header_size); + db->first_res_count = db->first_req_count; + db->first_buffer = cpu_to_le32(d_bus + sizeof(*db)); + + if (offset + rest < PAGE_SIZE) + length = rest; + else + length = PAGE_SIZE - offset; + + db->second_req_count = cpu_to_le16(length); + db->second_res_count = db->second_req_count; + page_bus = page_private(buffer->pages[page]); + db->second_buffer = cpu_to_le32(page_bus + offset); + + if (p->interrupt && length == rest) + db->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS); + + context_append(&ctx->context, d, z, header_z); + offset = (offset + length) & ~PAGE_MASK; + rest -= length; + page++; + } + + 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) +{ + struct iso_context *ctx = container_of(base, struct iso_context, base); + + if (base->type == FW_ISO_CONTEXT_TRANSMIT) + return ohci_queue_iso_transmit(base, packet, buffer, payload); + else if (ctx->context.ohci->version >= OHCI_VERSION_1_1) + return ohci_queue_iso_receive_dualbuffer(base, packet, + buffer, payload); + else + /* FIXME: Implement fallback for OHCI 1.0 controllers. */ + return -EINVAL; +} + +static const struct fw_card_driver ohci_driver = { + .name = ohci_driver_name, + .enable = ohci_enable, + .update_phy_reg = ohci_update_phy_reg, + .set_config_rom = ohci_set_config_rom, + .send_request = ohci_send_request, + .send_response = ohci_send_response, + .cancel_packet = ohci_cancel_packet, + .enable_phys_dma = ohci_enable_phys_dma, + .get_bus_time = ohci_get_bus_time, + + .allocate_iso_context = ohci_allocate_iso_context, + .free_iso_context = ohci_free_iso_context, + .queue_iso = ohci_queue_iso, + .start_iso = ohci_start_iso, + .stop_iso = ohci_stop_iso, +}; + +static int software_reset(struct fw_ohci *ohci) +{ + int i; + + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if ((reg_read(ohci, OHCI1394_HCControlSet) & + OHCI1394_HCControl_softReset) == 0) + return 0; + msleep(1); + } + + return -EBUSY; +} + +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; + u64 guid; + int err; + size_t size; + + ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); + if (ohci == NULL) { + fw_error("Could not malloc fw_ohci data.\n"); + return -ENOMEM; + } + + fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev); + + err = pci_enable_device(dev); + if (err) { + fw_error("Failed to enable OHCI hardware.\n"); + goto fail_put_card; + } + + pci_set_master(dev); + pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0); + pci_set_drvdata(dev, ohci); + + spin_lock_init(&ohci->lock); + + tasklet_init(&ohci->bus_reset_tasklet, + bus_reset_tasklet, (unsigned long)ohci); + + err = pci_request_region(dev, 0, ohci_driver_name); + if (err) { + fw_error("MMIO resource unavailable\n"); + goto fail_disable; + } + + ohci->registers = pci_iomap(dev, 0, OHCI1394_REGISTER_SIZE); + if (ohci->registers == NULL) { + fw_error("Failed to remap registers\n"); + err = -ENXIO; + goto fail_iomem; + } + + if (software_reset(ohci)) { + fw_error("Failed to reset ohci card.\n"); + err = -EBUSY; + goto fail_registers; + } + + /* + * Now enable LPS, which we need in order to start accessing + * most of the registers. In fact, on some cards (ALI M5251), + * accessing registers in the SClk domain without LPS enabled + * will lock up the machine. Wait 50msec to make sure we have + * full link enabled. + */ + reg_write(ohci, OHCI1394_HCControlSet, + OHCI1394_HCControl_LPS | + OHCI1394_HCControl_postedWriteEnable); + flush_writes(ohci); + msleep(50); + + reg_write(ohci, OHCI1394_HCControlClear, + OHCI1394_HCControl_noByteSwapData); + + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_rcvSelfID | + OHCI1394_LinkControl_cycleTimerEnable | + OHCI1394_LinkControl_cycleMaster); + + ar_context_init(&ohci->ar_request_ctx, ohci, + OHCI1394_AsReqRcvContextControlSet); + + ar_context_init(&ohci->ar_response_ctx, ohci, + OHCI1394_AsRspRcvContextControlSet); + + context_init(&ohci->at_request_ctx, ohci, AT_BUFFER_SIZE, + OHCI1394_AsReqTrContextControlSet, handle_at_packet); + + context_init(&ohci->at_response_ctx, ohci, AT_BUFFER_SIZE, + OHCI1394_AsRspTrContextControlSet, handle_at_packet); + + reg_write(ohci, OHCI1394_ATRetries, + OHCI1394_MAX_AT_REQ_RETRIES | + (OHCI1394_MAX_AT_RESP_RETRIES << 4) | + (OHCI1394_MAX_PHYS_RESP_RETRIES << 8)); + + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); + ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); + size = sizeof(struct iso_context) * hweight32(ohci->it_context_mask); + ohci->it_context_list = kzalloc(size, GFP_KERNEL); + + reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); + 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); + ohci->ir_context_list = kzalloc(size, GFP_KERNEL); + + if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) { + fw_error("Out of memory for it/ir contexts.\n"); + err = -ENOMEM; + goto fail_registers; + } + + /* self-id dma buffer allocation */ + ohci->self_id_cpu = dma_alloc_coherent(ohci->card.device, + SELF_ID_BUF_SIZE, + &ohci->self_id_bus, + GFP_KERNEL); + if (ohci->self_id_cpu == NULL) { + fw_error("Out of memory for self ID buffer.\n"); + err = -ENOMEM; + goto fail_registers; + } + + reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus); + reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000); + reg_write(ohci, OHCI1394_IntEventClear, ~0); + reg_write(ohci, OHCI1394_IntMaskClear, ~0); + reg_write(ohci, OHCI1394_IntMaskSet, + OHCI1394_selfIDComplete | + OHCI1394_RQPkt | OHCI1394_RSPkt | + OHCI1394_reqTxComplete | OHCI1394_respTxComplete | + OHCI1394_isochRx | OHCI1394_isochTx | + OHCI1394_masterIntEnable | + OHCI1394_cycle64Seconds); + + bus_options = reg_read(ohci, OHCI1394_BusOptions); + max_receive = (bus_options >> 12) & 0xf; + link_speed = bus_options & 0x7; + guid = ((u64) reg_read(ohci, OHCI1394_GUIDHi) << 32) | + reg_read(ohci, OHCI1394_GUIDLo); + + err = fw_card_add(&ohci->card, max_receive, link_speed, guid); + if (err < 0) + goto fail_self_id; + + ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; + fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n", + dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff); + + return 0; + + fail_self_id: + dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE, + ohci->self_id_cpu, ohci->self_id_bus); + fail_registers: + kfree(ohci->it_context_list); + kfree(ohci->ir_context_list); + pci_iounmap(dev, ohci->registers); + fail_iomem: + pci_release_region(dev, 0); + fail_disable: + pci_disable_device(dev); + fail_put_card: + fw_card_put(&ohci->card); + + return err; +} + +static void pci_remove(struct pci_dev *dev) +{ + struct fw_ohci *ohci; + + ohci = pci_get_drvdata(dev); + reg_write(ohci, OHCI1394_IntMaskClear, ~0); + flush_writes(ohci); + fw_core_remove_card(&ohci->card); + + /* + * FIXME: Fail all pending packets here, now that the upper + * layers can't queue any more. + */ + + software_reset(ohci); + free_irq(dev->irq, ohci); + dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE, + ohci->self_id_cpu, ohci->self_id_bus); + kfree(ohci->it_context_list); + kfree(ohci->ir_context_list); + pci_iounmap(dev, ohci->registers); + pci_release_region(dev, 0); + pci_disable_device(dev); + fw_card_put(&ohci->card); + + fw_notify("Removed fw-ohci device.\n"); +} + +static struct pci_device_id pci_table[] = { + { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_FIREWIRE_OHCI, ~0) }, + { } +}; + +MODULE_DEVICE_TABLE(pci, pci_table); + +static struct pci_driver fw_ohci_pci_driver = { + .name = ohci_driver_name, + .id_table = pci_table, + .probe = pci_probe, + .remove = pci_remove, +}; + +MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); +MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers"); +MODULE_LICENSE("GPL"); + +/* Provide a module alias so root-on-sbp2 initrds don't break. */ +#ifndef CONFIG_IEEE1394_OHCI1394_MODULE +MODULE_ALIAS("ohci1394"); +#endif + +static int __init fw_ohci_init(void) +{ + return pci_register_driver(&fw_ohci_pci_driver); +} + +static void __exit fw_ohci_cleanup(void) +{ + pci_unregister_driver(&fw_ohci_pci_driver); +} + +module_init(fw_ohci_init); +module_exit(fw_ohci_cleanup); diff --git a/drivers/firewire/fw-ohci.h b/drivers/firewire/fw-ohci.h new file mode 100644 index 000000000000..fa15706397d7 --- /dev/null +++ b/drivers/firewire/fw-ohci.h @@ -0,0 +1,153 @@ +#ifndef __fw_ohci_h +#define __fw_ohci_h + +/* OHCI register map */ + +#define OHCI1394_Version 0x000 +#define OHCI1394_GUID_ROM 0x004 +#define OHCI1394_ATRetries 0x008 +#define OHCI1394_CSRData 0x00C +#define OHCI1394_CSRCompareData 0x010 +#define OHCI1394_CSRControl 0x014 +#define OHCI1394_ConfigROMhdr 0x018 +#define OHCI1394_BusID 0x01C +#define OHCI1394_BusOptions 0x020 +#define OHCI1394_GUIDHi 0x024 +#define OHCI1394_GUIDLo 0x028 +#define OHCI1394_ConfigROMmap 0x034 +#define OHCI1394_PostedWriteAddressLo 0x038 +#define OHCI1394_PostedWriteAddressHi 0x03C +#define OHCI1394_VendorID 0x040 +#define OHCI1394_HCControlSet 0x050 +#define OHCI1394_HCControlClear 0x054 +#define OHCI1394_HCControl_BIBimageValid 0x80000000 +#define OHCI1394_HCControl_noByteSwapData 0x40000000 +#define OHCI1394_HCControl_programPhyEnable 0x00800000 +#define OHCI1394_HCControl_aPhyEnhanceEnable 0x00400000 +#define OHCI1394_HCControl_LPS 0x00080000 +#define OHCI1394_HCControl_postedWriteEnable 0x00040000 +#define OHCI1394_HCControl_linkEnable 0x00020000 +#define OHCI1394_HCControl_softReset 0x00010000 +#define OHCI1394_SelfIDBuffer 0x064 +#define OHCI1394_SelfIDCount 0x068 +#define OHCI1394_IRMultiChanMaskHiSet 0x070 +#define OHCI1394_IRMultiChanMaskHiClear 0x074 +#define OHCI1394_IRMultiChanMaskLoSet 0x078 +#define OHCI1394_IRMultiChanMaskLoClear 0x07C +#define OHCI1394_IntEventSet 0x080 +#define OHCI1394_IntEventClear 0x084 +#define OHCI1394_IntMaskSet 0x088 +#define OHCI1394_IntMaskClear 0x08C +#define OHCI1394_IsoXmitIntEventSet 0x090 +#define OHCI1394_IsoXmitIntEventClear 0x094 +#define OHCI1394_IsoXmitIntMaskSet 0x098 +#define OHCI1394_IsoXmitIntMaskClear 0x09C +#define OHCI1394_IsoRecvIntEventSet 0x0A0 +#define OHCI1394_IsoRecvIntEventClear 0x0A4 +#define OHCI1394_IsoRecvIntMaskSet 0x0A8 +#define OHCI1394_IsoRecvIntMaskClear 0x0AC +#define OHCI1394_InitialBandwidthAvailable 0x0B0 +#define OHCI1394_InitialChannelsAvailableHi 0x0B4 +#define OHCI1394_InitialChannelsAvailableLo 0x0B8 +#define OHCI1394_FairnessControl 0x0DC +#define OHCI1394_LinkControlSet 0x0E0 +#define OHCI1394_LinkControlClear 0x0E4 +#define OHCI1394_LinkControl_rcvSelfID (1 << 9) +#define OHCI1394_LinkControl_rcvPhyPkt (1 << 10) +#define OHCI1394_LinkControl_cycleTimerEnable (1 << 20) +#define OHCI1394_LinkControl_cycleMaster (1 << 21) +#define OHCI1394_LinkControl_cycleSource (1 << 22) +#define OHCI1394_NodeID 0x0E8 +#define OHCI1394_NodeID_idValid 0x80000000 +#define OHCI1394_PhyControl 0x0EC +#define OHCI1394_PhyControl_Read(addr) (((addr) << 8) | 0x00008000) +#define OHCI1394_PhyControl_ReadDone 0x80000000 +#define OHCI1394_PhyControl_ReadData(r) (((r) & 0x00ff0000) >> 16) +#define OHCI1394_PhyControl_Write(addr, data) (((addr) << 8) | (data) | 0x00004000) +#define OHCI1394_PhyControl_WriteDone 0x00004000 +#define OHCI1394_IsochronousCycleTimer 0x0F0 +#define OHCI1394_AsReqFilterHiSet 0x100 +#define OHCI1394_AsReqFilterHiClear 0x104 +#define OHCI1394_AsReqFilterLoSet 0x108 +#define OHCI1394_AsReqFilterLoClear 0x10C +#define OHCI1394_PhyReqFilterHiSet 0x110 +#define OHCI1394_PhyReqFilterHiClear 0x114 +#define OHCI1394_PhyReqFilterLoSet 0x118 +#define OHCI1394_PhyReqFilterLoClear 0x11C +#define OHCI1394_PhyUpperBound 0x120 + +#define OHCI1394_AsReqTrContextBase 0x180 +#define OHCI1394_AsReqTrContextControlSet 0x180 +#define OHCI1394_AsReqTrContextControlClear 0x184 +#define OHCI1394_AsReqTrCommandPtr 0x18C + +#define OHCI1394_AsRspTrContextBase 0x1A0 +#define OHCI1394_AsRspTrContextControlSet 0x1A0 +#define OHCI1394_AsRspTrContextControlClear 0x1A4 +#define OHCI1394_AsRspTrCommandPtr 0x1AC + +#define OHCI1394_AsReqRcvContextBase 0x1C0 +#define OHCI1394_AsReqRcvContextControlSet 0x1C0 +#define OHCI1394_AsReqRcvContextControlClear 0x1C4 +#define OHCI1394_AsReqRcvCommandPtr 0x1CC + +#define OHCI1394_AsRspRcvContextBase 0x1E0 +#define OHCI1394_AsRspRcvContextControlSet 0x1E0 +#define OHCI1394_AsRspRcvContextControlClear 0x1E4 +#define OHCI1394_AsRspRcvCommandPtr 0x1EC + +/* Isochronous transmit registers */ +#define OHCI1394_IsoXmitContextBase(n) (0x200 + 16 * (n)) +#define OHCI1394_IsoXmitContextControlSet(n) (0x200 + 16 * (n)) +#define OHCI1394_IsoXmitContextControlClear(n) (0x204 + 16 * (n)) +#define OHCI1394_IsoXmitCommandPtr(n) (0x20C + 16 * (n)) + +/* Isochronous receive registers */ +#define OHCI1394_IsoRcvContextBase(n) (0x400 + 32 * (n)) +#define OHCI1394_IsoRcvContextControlSet(n) (0x400 + 32 * (n)) +#define OHCI1394_IsoRcvContextControlClear(n) (0x404 + 32 * (n)) +#define OHCI1394_IsoRcvCommandPtr(n) (0x40C + 32 * (n)) +#define OHCI1394_IsoRcvContextMatch(n) (0x410 + 32 * (n)) + +/* Interrupts Mask/Events */ +#define OHCI1394_reqTxComplete 0x00000001 +#define OHCI1394_respTxComplete 0x00000002 +#define OHCI1394_ARRQ 0x00000004 +#define OHCI1394_ARRS 0x00000008 +#define OHCI1394_RQPkt 0x00000010 +#define OHCI1394_RSPkt 0x00000020 +#define OHCI1394_isochTx 0x00000040 +#define OHCI1394_isochRx 0x00000080 +#define OHCI1394_postedWriteErr 0x00000100 +#define OHCI1394_lockRespErr 0x00000200 +#define OHCI1394_selfIDComplete 0x00010000 +#define OHCI1394_busReset 0x00020000 +#define OHCI1394_phy 0x00080000 +#define OHCI1394_cycleSynch 0x00100000 +#define OHCI1394_cycle64Seconds 0x00200000 +#define OHCI1394_cycleLost 0x00400000 +#define OHCI1394_cycleInconsistent 0x00800000 +#define OHCI1394_unrecoverableError 0x01000000 +#define OHCI1394_cycleTooLong 0x02000000 +#define OHCI1394_phyRegRcvd 0x04000000 +#define OHCI1394_masterIntEnable 0x80000000 + +#define OHCI1394_evt_no_status 0x0 +#define OHCI1394_evt_long_packet 0x2 +#define OHCI1394_evt_missing_ack 0x3 +#define OHCI1394_evt_underrun 0x4 +#define OHCI1394_evt_overrun 0x5 +#define OHCI1394_evt_descriptor_read 0x6 +#define OHCI1394_evt_data_read 0x7 +#define OHCI1394_evt_data_write 0x8 +#define OHCI1394_evt_bus_reset 0x9 +#define OHCI1394_evt_timeout 0xa +#define OHCI1394_evt_tcode_err 0xb +#define OHCI1394_evt_reserved_b 0xc +#define OHCI1394_evt_reserved_c 0xd +#define OHCI1394_evt_unknown 0xe +#define OHCI1394_evt_flushed 0xf + +#define OHCI1394_phy_tcode 0xe + +#endif /* __fw_ohci_h */ diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c new file mode 100644 index 000000000000..68300414e5f4 --- /dev/null +++ b/drivers/firewire/fw-sbp2.c @@ -0,0 +1,1147 @@ +/* + * SBP2 driver (SCSI over IEEE1394) + * + * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * The basic structure of this driver is based on the old storage driver, + * drivers/ieee1394/sbp2.c, originally written by + * James Goodwin <jamesg@filanet.com> + * with later contributions and ongoing maintenance from + * Ben Collins <bcollins@debian.org>, + * Stefan Richter <stefanr@s5r6.in-berlin.de> + * and many others. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/device.h> +#include <linux/scatterlist.h> +#include <linux/dma-mapping.h> +#include <linux/timer.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_dbg.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> + +#include "fw-transaction.h" +#include "fw-topology.h" +#include "fw-device.h" + +/* I don't know why the SCSI stack doesn't define something like this... */ +typedef void (*scsi_done_fn_t)(struct scsi_cmnd *); + +static const char sbp2_driver_name[] = "sbp2"; + +struct sbp2_device { + struct kref kref; + struct fw_unit *unit; + struct fw_address_handler address_handler; + struct list_head orb_list; + u64 management_agent_address; + u64 command_block_agent_address; + u32 workarounds; + int login_id; + + /* + * We cache these addresses and only update them once we've + * logged in or reconnected to the sbp2 device. That way, any + * IO to the device will automatically fail and get retried if + * it happens in a window where the device is not ready to + * handle it (e.g. after a bus reset but before we reconnect). + */ + int node_id; + int address_high; + int generation; + + int retries; + struct delayed_work work; +}; + +#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 +#define SBP2_MAX_SECTORS 255 /* Max sectors supported */ +#define SBP2_ORB_TIMEOUT 2000 /* Timeout in ms */ + +#define SBP2_ORB_NULL 0x80000000 + +#define SBP2_DIRECTION_TO_MEDIA 0x0 +#define SBP2_DIRECTION_FROM_MEDIA 0x1 + +/* Unit directory keys */ +#define SBP2_COMMAND_SET_SPECIFIER 0x38 +#define SBP2_COMMAND_SET 0x39 +#define SBP2_COMMAND_SET_REVISION 0x3b +#define SBP2_FIRMWARE_REVISION 0x3c + +/* Flags for detected oddities and brokeness */ +#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1 +#define SBP2_WORKAROUND_INQUIRY_36 0x2 +#define SBP2_WORKAROUND_MODE_SENSE_8 0x4 +#define SBP2_WORKAROUND_FIX_CAPACITY 0x8 +#define SBP2_WORKAROUND_OVERRIDE 0x100 + +/* Management orb opcodes */ +#define SBP2_LOGIN_REQUEST 0x0 +#define SBP2_QUERY_LOGINS_REQUEST 0x1 +#define SBP2_RECONNECT_REQUEST 0x3 +#define SBP2_SET_PASSWORD_REQUEST 0x4 +#define SBP2_LOGOUT_REQUEST 0x7 +#define SBP2_ABORT_TASK_REQUEST 0xb +#define SBP2_ABORT_TASK_SET 0xc +#define SBP2_LOGICAL_UNIT_RESET 0xe +#define SBP2_TARGET_RESET_REQUEST 0xf + +/* Offsets for command block agent registers */ +#define SBP2_AGENT_STATE 0x00 +#define SBP2_AGENT_RESET 0x04 +#define SBP2_ORB_POINTER 0x08 +#define SBP2_DOORBELL 0x10 +#define SBP2_UNSOLICITED_STATUS_ENABLE 0x14 + +/* Status write response codes */ +#define SBP2_STATUS_REQUEST_COMPLETE 0x0 +#define SBP2_STATUS_TRANSPORT_FAILURE 0x1 +#define SBP2_STATUS_ILLEGAL_REQUEST 0x2 +#define SBP2_STATUS_VENDOR_DEPENDENT 0x3 + +#define STATUS_GET_ORB_HIGH(v) ((v).status & 0xffff) +#define STATUS_GET_SBP_STATUS(v) (((v).status >> 16) & 0xff) +#define STATUS_GET_LEN(v) (((v).status >> 24) & 0x07) +#define STATUS_GET_DEAD(v) (((v).status >> 27) & 0x01) +#define STATUS_GET_RESPONSE(v) (((v).status >> 28) & 0x03) +#define STATUS_GET_SOURCE(v) (((v).status >> 30) & 0x03) +#define STATUS_GET_ORB_LOW(v) ((v).orb_low) +#define STATUS_GET_DATA(v) ((v).data) + +struct sbp2_status { + u32 status; + u32 orb_low; + u8 data[24]; +}; + +struct sbp2_pointer { + u32 high; + u32 low; +}; + +struct sbp2_orb { + struct fw_transaction t; + dma_addr_t request_bus; + int rcode; + struct sbp2_pointer pointer; + void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status); + struct list_head link; +}; + +#define MANAGEMENT_ORB_LUN(v) ((v)) +#define MANAGEMENT_ORB_FUNCTION(v) ((v) << 16) +#define MANAGEMENT_ORB_RECONNECT(v) ((v) << 20) +#define MANAGEMENT_ORB_EXCLUSIVE ((1) << 28) +#define MANAGEMENT_ORB_REQUEST_FORMAT(v) ((v) << 29) +#define MANAGEMENT_ORB_NOTIFY ((1) << 31) + +#define MANAGEMENT_ORB_RESPONSE_LENGTH(v) ((v)) +#define MANAGEMENT_ORB_PASSWORD_LENGTH(v) ((v) << 16) + +struct sbp2_management_orb { + struct sbp2_orb base; + struct { + struct sbp2_pointer password; + struct sbp2_pointer response; + u32 misc; + u32 length; + struct sbp2_pointer status_fifo; + } request; + __be32 response[4]; + dma_addr_t response_bus; + struct completion done; + struct sbp2_status status; +}; + +#define LOGIN_RESPONSE_GET_LOGIN_ID(v) ((v).misc & 0xffff) +#define LOGIN_RESPONSE_GET_LENGTH(v) (((v).misc >> 16) & 0xffff) + +struct sbp2_login_response { + u32 misc; + struct sbp2_pointer command_block_agent; + u32 reconnect_hold; +}; +#define COMMAND_ORB_DATA_SIZE(v) ((v)) +#define COMMAND_ORB_PAGE_SIZE(v) ((v) << 16) +#define COMMAND_ORB_PAGE_TABLE_PRESENT ((1) << 19) +#define COMMAND_ORB_MAX_PAYLOAD(v) ((v) << 20) +#define COMMAND_ORB_SPEED(v) ((v) << 24) +#define COMMAND_ORB_DIRECTION(v) ((v) << 27) +#define COMMAND_ORB_REQUEST_FORMAT(v) ((v) << 29) +#define COMMAND_ORB_NOTIFY ((1) << 31) + +struct sbp2_command_orb { + struct sbp2_orb base; + struct { + struct sbp2_pointer next; + struct sbp2_pointer data_descriptor; + u32 misc; + u8 command_block[12]; + } request; + struct scsi_cmnd *cmd; + scsi_done_fn_t done; + struct fw_unit *unit; + + struct sbp2_pointer page_table[SG_ALL]; + dma_addr_t page_table_bus; + dma_addr_t request_buffer_bus; +}; + +/* + * List of devices with known bugs. + * + * The firmware_revision field, masked with 0xffff00, is the best + * indicator for the type of bridge chip of a device. It yields a few + * false positives but this did not break correctly behaving devices + * so far. We use ~0 as a wildcard, since the 24 bit values we get + * from the config rom can never match that. + */ +static const struct { + u32 firmware_revision; + u32 model; + unsigned workarounds; +} sbp2_workarounds_table[] = { + /* DViCO Momobay CX-1 with TSB42AA9 bridge */ { + .firmware_revision = 0x002800, + .model = 0x001010, + .workarounds = SBP2_WORKAROUND_INQUIRY_36 | + SBP2_WORKAROUND_MODE_SENSE_8, + }, + /* Initio bridges, actually only needed for some older ones */ { + .firmware_revision = 0x000200, + .model = ~0, + .workarounds = SBP2_WORKAROUND_INQUIRY_36, + }, + /* Symbios bridge */ { + .firmware_revision = 0xa0b800, + .model = ~0, + .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, + }, + + /* + * There are iPods (2nd gen, 3rd gen) with model_id == 0, but + * these iPods do not feature the read_capacity bug according + * to one report. Read_capacity behaviour as well as model_id + * could change due to Apple-supplied firmware updates though. + */ + + /* iPod 4th generation. */ { + .firmware_revision = 0x0a2700, + .model = 0x000021, + .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, + }, + /* iPod mini */ { + .firmware_revision = 0x0a2700, + .model = 0x000023, + .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, + }, + /* iPod Photo */ { + .firmware_revision = 0x0a2700, + .model = 0x00007e, + .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, + } +}; + +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_device *sd = callback_data; + struct sbp2_orb *orb; + struct sbp2_status status; + size_t header_size; + unsigned long flags; + + if (tcode != TCODE_WRITE_BLOCK_REQUEST || + length == 0 || length > sizeof(status)) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + return; + } + + header_size = min(length, 2 * sizeof(u32)); + fw_memcpy_from_be32(&status, payload, header_size); + if (length > header_size) + memcpy(status.data, payload + 8, length - header_size); + if (STATUS_GET_SOURCE(status) == 2 || STATUS_GET_SOURCE(status) == 3) { + fw_notify("non-orb related status write, not handled\n"); + fw_send_response(card, request, RCODE_COMPLETE); + return; + } + + /* Lookup the orb corresponding to this status write. */ + spin_lock_irqsave(&card->lock, flags); + list_for_each_entry(orb, &sd->orb_list, link) { + if (STATUS_GET_ORB_HIGH(status) == 0 && + STATUS_GET_ORB_LOW(status) == orb->request_bus && + orb->rcode == RCODE_COMPLETE) { + list_del(&orb->link); + break; + } + } + spin_unlock_irqrestore(&card->lock, flags); + + if (&orb->link != &sd->orb_list) + orb->callback(orb, &status); + else + fw_error("status write for unknown orb\n"); + + fw_send_response(card, request, RCODE_COMPLETE); +} + +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; + + orb->rcode = rcode; + if (rcode != RCODE_COMPLETE) { + spin_lock_irqsave(&card->lock, flags); + list_del(&orb->link); + spin_unlock_irqrestore(&card->lock, flags); + orb->callback(orb, NULL); + } +} + +static void +sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit, + int node_id, int generation, u64 offset) +{ + struct fw_device *device = fw_device(unit->device.parent); + struct sbp2_device *sd = unit->device.driver_data; + unsigned long flags; + + orb->pointer.high = 0; + orb->pointer.low = orb->request_bus; + fw_memcpy_to_be32(&orb->pointer, &orb->pointer, sizeof(orb->pointer)); + + spin_lock_irqsave(&device->card->lock, flags); + list_add_tail(&orb->link, &sd->orb_list); + spin_unlock_irqrestore(&device->card->lock, flags); + + fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, + node_id, generation, + device->node->max_speed, offset, + &orb->pointer, sizeof(orb->pointer), + complete_transaction, orb); +} + +static int sbp2_cancel_orbs(struct fw_unit *unit) +{ + struct fw_device *device = fw_device(unit->device.parent); + struct sbp2_device *sd = unit->device.driver_data; + struct sbp2_orb *orb, *next; + struct list_head list; + unsigned long flags; + int retval = -ENOENT; + + INIT_LIST_HEAD(&list); + spin_lock_irqsave(&device->card->lock, flags); + list_splice_init(&sd->orb_list, &list); + spin_unlock_irqrestore(&device->card->lock, flags); + + list_for_each_entry_safe(orb, next, &list, link) { + retval = 0; + if (fw_cancel_transaction(device->card, &orb->t) == 0) + continue; + + orb->rcode = RCODE_CANCELLED; + orb->callback(orb, NULL); + } + + return retval; +} + +static void +complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) +{ + struct sbp2_management_orb *orb = + (struct sbp2_management_orb *)base_orb; + + if (status) + memcpy(&orb->status, status, sizeof(*status)); + complete(&orb->done); +} + +static int +sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation, + int function, int lun, void *response) +{ + struct fw_device *device = fw_device(unit->device.parent); + struct sbp2_device *sd = unit->device.driver_data; + struct sbp2_management_orb *orb; + int retval = -ENOMEM; + + orb = kzalloc(sizeof(*orb), GFP_ATOMIC); + if (orb == NULL) + return -ENOMEM; + + /* + * The sbp2 device is going to send a block read request to + * read out the request from host memory, so map it for dma. + */ + orb->base.request_bus = + dma_map_single(device->card->device, &orb->request, + sizeof(orb->request), DMA_TO_DEVICE); + if (dma_mapping_error(orb->base.request_bus)) + goto out; + + orb->response_bus = + dma_map_single(device->card->device, &orb->response, + sizeof(orb->response), DMA_FROM_DEVICE); + if (dma_mapping_error(orb->response_bus)) + goto out; + + orb->request.response.high = 0; + orb->request.response.low = orb->response_bus; + + orb->request.misc = + MANAGEMENT_ORB_NOTIFY | + MANAGEMENT_ORB_FUNCTION(function) | + MANAGEMENT_ORB_LUN(lun); + orb->request.length = + MANAGEMENT_ORB_RESPONSE_LENGTH(sizeof(orb->response)); + + orb->request.status_fifo.high = sd->address_handler.offset >> 32; + orb->request.status_fifo.low = sd->address_handler.offset; + + /* + * FIXME: Yeah, ok this isn't elegant, we hardwire exclusive + * login and 1 second reconnect time. The reconnect setting + * is probably fine, but the exclusive login should be an option. + */ + if (function == SBP2_LOGIN_REQUEST) { + orb->request.misc |= + MANAGEMENT_ORB_EXCLUSIVE | + MANAGEMENT_ORB_RECONNECT(0); + } + + fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request)); + + init_completion(&orb->done); + orb->base.callback = complete_management_orb; + + sbp2_send_orb(&orb->base, unit, + node_id, generation, sd->management_agent_address); + + wait_for_completion_timeout(&orb->done, + msecs_to_jiffies(SBP2_ORB_TIMEOUT)); + + retval = -EIO; + if (sbp2_cancel_orbs(unit) == 0) { + fw_error("orb reply timed out, rcode=0x%02x\n", + orb->base.rcode); + goto out; + } + + if (orb->base.rcode != RCODE_COMPLETE) { + fw_error("management write failed, rcode 0x%02x\n", + orb->base.rcode); + goto out; + } + + if (STATUS_GET_RESPONSE(orb->status) != 0 || + STATUS_GET_SBP_STATUS(orb->status) != 0) { + fw_error("error status: %d:%d\n", + STATUS_GET_RESPONSE(orb->status), + STATUS_GET_SBP_STATUS(orb->status)); + goto out; + } + + retval = 0; + out: + dma_unmap_single(device->card->device, orb->base.request_bus, + sizeof(orb->request), DMA_TO_DEVICE); + dma_unmap_single(device->card->device, orb->response_bus, + sizeof(orb->response), DMA_FROM_DEVICE); + + if (response) + fw_memcpy_from_be32(response, + orb->response, sizeof(orb->response)); + kfree(orb); + + return retval; +} + +static void +complete_agent_reset_write(struct fw_card *card, int rcode, + void *payload, size_t length, void *data) +{ + struct fw_transaction *t = data; + + kfree(t); +} + +static int sbp2_agent_reset(struct fw_unit *unit) +{ + struct fw_device *device = fw_device(unit->device.parent); + struct sbp2_device *sd = unit->device.driver_data; + struct fw_transaction *t; + static u32 zero; + + t = kzalloc(sizeof(*t), GFP_ATOMIC); + if (t == NULL) + return -ENOMEM; + + fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST, + sd->node_id, sd->generation, SCODE_400, + sd->command_block_agent_address + SBP2_AGENT_RESET, + &zero, sizeof(zero), complete_agent_reset_write, t); + + return 0; +} + +static void sbp2_reconnect(struct work_struct *work); +static struct scsi_host_template scsi_driver_template; + +static void +release_sbp2_device(struct kref *kref) +{ + struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref); + struct Scsi_Host *host = + container_of((void *)sd, struct Scsi_Host, hostdata[0]); + + sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation, + SBP2_LOGOUT_REQUEST, sd->login_id, NULL); + + scsi_remove_host(host); + fw_core_remove_address_handler(&sd->address_handler); + fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id); + put_device(&sd->unit->device); + scsi_host_put(host); +} + +static void sbp2_login(struct work_struct *work) +{ + struct sbp2_device *sd = + container_of(work, struct sbp2_device, work.work); + struct Scsi_Host *host = + container_of((void *)sd, struct Scsi_Host, hostdata[0]); + struct fw_unit *unit = sd->unit; + struct fw_device *device = fw_device(unit->device.parent); + struct sbp2_login_response response; + int generation, node_id, local_node_id, lun, retval; + + /* FIXME: Make this work for multi-lun devices. */ + lun = 0; + + generation = device->card->generation; + node_id = device->node->node_id; + local_node_id = device->card->local_node->node_id; + + if (sbp2_send_management_orb(unit, node_id, generation, + SBP2_LOGIN_REQUEST, lun, &response) < 0) { + if (sd->retries++ < 5) { + schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5)); + } else { + fw_error("failed to login to %s\n", + unit->device.bus_id); + kref_put(&sd->kref, release_sbp2_device); + } + return; + } + + sd->generation = generation; + sd->node_id = node_id; + sd->address_high = local_node_id << 16; + + /* Get command block agent offset and login id. */ + sd->command_block_agent_address = + ((u64) (response.command_block_agent.high & 0xffff) << 32) | + response.command_block_agent.low; + sd->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response); + + fw_notify("logged in to sbp2 unit %s (%d retries)\n", + unit->device.bus_id, sd->retries); + fw_notify(" - management_agent_address: 0x%012llx\n", + (unsigned long long) sd->management_agent_address); + fw_notify(" - command_block_agent_address: 0x%012llx\n", + (unsigned long long) sd->command_block_agent_address); + fw_notify(" - status write address: 0x%012llx\n", + (unsigned long long) sd->address_handler.offset); + +#if 0 + /* FIXME: The linux1394 sbp2 does this last step. */ + sbp2_set_busy_timeout(scsi_id); +#endif + + PREPARE_DELAYED_WORK(&sd->work, sbp2_reconnect); + sbp2_agent_reset(unit); + + /* FIXME: Loop over luns here. */ + lun = 0; + retval = scsi_add_device(host, 0, 0, lun); + if (retval < 0) { + sbp2_send_management_orb(unit, sd->node_id, sd->generation, + SBP2_LOGOUT_REQUEST, sd->login_id, + NULL); + /* + * Set this back to sbp2_login so we fall back and + * retry login on bus reset. + */ + PREPARE_DELAYED_WORK(&sd->work, sbp2_login); + } + kref_put(&sd->kref, release_sbp2_device); +} + +static int sbp2_probe(struct device *dev) +{ + struct fw_unit *unit = fw_unit(dev); + struct fw_device *device = fw_device(unit->device.parent); + struct sbp2_device *sd; + struct fw_csr_iterator ci; + struct Scsi_Host *host; + int i, key, value, err; + u32 model, firmware_revision; + + err = -ENOMEM; + host = scsi_host_alloc(&scsi_driver_template, sizeof(*sd)); + if (host == NULL) + goto fail; + + sd = (struct sbp2_device *) host->hostdata; + unit->device.driver_data = sd; + sd->unit = unit; + INIT_LIST_HEAD(&sd->orb_list); + kref_init(&sd->kref); + + sd->address_handler.length = 0x100; + sd->address_handler.address_callback = sbp2_status_write; + sd->address_handler.callback_data = sd; + + err = fw_core_add_address_handler(&sd->address_handler, + &fw_high_memory_region); + if (err < 0) + goto fail_host; + + err = fw_device_enable_phys_dma(device); + if (err < 0) + goto fail_address_handler; + + err = scsi_add_host(host, &unit->device); + if (err < 0) + goto fail_address_handler; + + /* + * Scan unit directory to get management agent address, + * firmware revison and model. Initialize firmware_revision + * and model to values that wont match anything in our table. + */ + firmware_revision = 0xff000000; + model = 0xff000000; + fw_csr_iterator_init(&ci, unit->directory); + while (fw_csr_iterator_next(&ci, &key, &value)) { + switch (key) { + case CSR_DEPENDENT_INFO | CSR_OFFSET: + sd->management_agent_address = + 0xfffff0000000ULL + 4 * value; + break; + case SBP2_FIRMWARE_REVISION: + firmware_revision = value; + break; + case CSR_MODEL: + model = value; + break; + } + } + + for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) { + if (sbp2_workarounds_table[i].firmware_revision != + (firmware_revision & 0xffffff00)) + continue; + if (sbp2_workarounds_table[i].model != model && + sbp2_workarounds_table[i].model != ~0) + continue; + sd->workarounds |= sbp2_workarounds_table[i].workarounds; + break; + } + + if (sd->workarounds) + fw_notify("Workarounds for node %s: 0x%x " + "(firmware_revision 0x%06x, model_id 0x%06x)\n", + unit->device.bus_id, + sd->workarounds, firmware_revision, model); + + get_device(&unit->device); + + /* + * We schedule work to do the login so we can easily + * reschedule retries. Always get the ref before scheduling + * work. + */ + INIT_DELAYED_WORK(&sd->work, sbp2_login); + if (schedule_delayed_work(&sd->work, 0)) + kref_get(&sd->kref); + + return 0; + + fail_address_handler: + fw_core_remove_address_handler(&sd->address_handler); + fail_host: + scsi_host_put(host); + fail: + return err; +} + +static int sbp2_remove(struct device *dev) +{ + struct fw_unit *unit = fw_unit(dev); + struct sbp2_device *sd = unit->device.driver_data; + + kref_put(&sd->kref, release_sbp2_device); + + return 0; +} + +static void sbp2_reconnect(struct work_struct *work) +{ + struct sbp2_device *sd = + container_of(work, struct sbp2_device, work.work); + struct fw_unit *unit = sd->unit; + struct fw_device *device = fw_device(unit->device.parent); + int generation, node_id, local_node_id; + + generation = device->card->generation; + node_id = device->node->node_id; + local_node_id = device->card->local_node->node_id; + + if (sbp2_send_management_orb(unit, node_id, generation, + SBP2_RECONNECT_REQUEST, + sd->login_id, NULL) < 0) { + if (sd->retries++ >= 5) { + fw_error("failed to reconnect to %s\n", + unit->device.bus_id); + /* Fall back and try to log in again. */ + sd->retries = 0; + PREPARE_DELAYED_WORK(&sd->work, sbp2_login); + } + schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5)); + return; + } + + sd->generation = generation; + sd->node_id = node_id; + sd->address_high = local_node_id << 16; + + fw_notify("reconnected to unit %s (%d retries)\n", + unit->device.bus_id, sd->retries); + sbp2_agent_reset(unit); + sbp2_cancel_orbs(unit); + kref_put(&sd->kref, release_sbp2_device); +} + +static void sbp2_update(struct fw_unit *unit) +{ + struct fw_device *device = fw_device(unit->device.parent); + struct sbp2_device *sd = unit->device.driver_data; + + sd->retries = 0; + fw_device_enable_phys_dma(device); + if (schedule_delayed_work(&sd->work, 0)) + kref_get(&sd->kref); +} + +#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e +#define SBP2_SW_VERSION_ENTRY 0x00010483 + +static const struct fw_device_id sbp2_id_table[] = { + { + .match_flags = FW_MATCH_SPECIFIER_ID | FW_MATCH_VERSION, + .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY, + .version = SBP2_SW_VERSION_ENTRY, + }, + { } +}; + +static struct fw_driver sbp2_driver = { + .driver = { + .owner = THIS_MODULE, + .name = sbp2_driver_name, + .bus = &fw_bus_type, + .probe = sbp2_probe, + .remove = sbp2_remove, + }, + .update = sbp2_update, + .id_table = sbp2_id_table, +}; + +static unsigned int +sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data) +{ + int sam_status; + + sense_data[0] = 0x70; + sense_data[1] = 0x0; + sense_data[2] = sbp2_status[1]; + sense_data[3] = sbp2_status[4]; + sense_data[4] = sbp2_status[5]; + sense_data[5] = sbp2_status[6]; + sense_data[6] = sbp2_status[7]; + sense_data[7] = 10; + sense_data[8] = sbp2_status[8]; + sense_data[9] = sbp2_status[9]; + sense_data[10] = sbp2_status[10]; + sense_data[11] = sbp2_status[11]; + sense_data[12] = sbp2_status[2]; + sense_data[13] = sbp2_status[3]; + sense_data[14] = sbp2_status[12]; + sense_data[15] = sbp2_status[13]; + + sam_status = sbp2_status[0] & 0x3f; + + switch (sam_status) { + case SAM_STAT_GOOD: + case SAM_STAT_CHECK_CONDITION: + case SAM_STAT_CONDITION_MET: + case SAM_STAT_BUSY: + case SAM_STAT_RESERVATION_CONFLICT: + case SAM_STAT_COMMAND_TERMINATED: + return DID_OK << 16 | sam_status; + + default: + return DID_ERROR << 16; + } +} + +static void +complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) +{ + struct sbp2_command_orb *orb = (struct sbp2_command_orb *)base_orb; + struct fw_unit *unit = orb->unit; + struct fw_device *device = fw_device(unit->device.parent); + struct scatterlist *sg; + int result; + + if (status != NULL) { + if (STATUS_GET_DEAD(*status)) + sbp2_agent_reset(unit); + + switch (STATUS_GET_RESPONSE(*status)) { + case SBP2_STATUS_REQUEST_COMPLETE: + result = DID_OK << 16; + break; + case SBP2_STATUS_TRANSPORT_FAILURE: + result = DID_BUS_BUSY << 16; + break; + case SBP2_STATUS_ILLEGAL_REQUEST: + case SBP2_STATUS_VENDOR_DEPENDENT: + default: + result = DID_ERROR << 16; + break; + } + + if (result == DID_OK << 16 && STATUS_GET_LEN(*status) > 1) + result = sbp2_status_to_sense_data(STATUS_GET_DATA(*status), + orb->cmd->sense_buffer); + } else { + /* + * If the orb completes with status == NULL, something + * went wrong, typically a bus reset happened mid-orb + * or when sending the write (less likely). + */ + result = DID_BUS_BUSY << 16; + } + + dma_unmap_single(device->card->device, orb->base.request_bus, + sizeof(orb->request), DMA_TO_DEVICE); + + if (orb->cmd->use_sg > 0) { + sg = (struct scatterlist *)orb->cmd->request_buffer; + dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg, + orb->cmd->sc_data_direction); + } + + if (orb->page_table_bus != 0) + dma_unmap_single(device->card->device, orb->page_table_bus, + sizeof(orb->page_table_bus), DMA_TO_DEVICE); + + if (orb->request_buffer_bus != 0) + dma_unmap_single(device->card->device, orb->request_buffer_bus, + sizeof(orb->request_buffer_bus), + DMA_FROM_DEVICE); + + orb->cmd->result = result; + orb->done(orb->cmd); + kfree(orb); +} + +static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) +{ + struct sbp2_device *sd = + (struct sbp2_device *)orb->cmd->device->host->hostdata; + struct fw_unit *unit = sd->unit; + struct fw_device *device = fw_device(unit->device.parent); + struct scatterlist *sg; + int sg_len, l, i, j, count; + size_t size; + dma_addr_t sg_addr; + + sg = (struct scatterlist *)orb->cmd->request_buffer; + count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg, + orb->cmd->sc_data_direction); + if (count == 0) + goto fail; + + /* + * Handle the special case where there is only one element in + * the scatter list by converting it to an immediate block + * request. This is also a workaround for broken devices such + * as the second generation iPod which doesn't support page + * tables. + */ + if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) { + orb->request.data_descriptor.high = sd->address_high; + orb->request.data_descriptor.low = sg_dma_address(sg); + orb->request.misc |= + COMMAND_ORB_DATA_SIZE(sg_dma_len(sg)); + return 0; + } + + /* + * Convert the scatterlist to an sbp2 page table. If any + * scatterlist entries are too big for sbp2, we split them as we + * go. Even if we ask the block I/O layer to not give us sg + * elements larger than 65535 bytes, some IOMMUs may merge sg elements + * during DMA mapping, and Linux currently doesn't prevent this. + */ + for (i = 0, j = 0; i < count; i++) { + sg_len = sg_dma_len(sg + i); + sg_addr = sg_dma_address(sg + i); + while (sg_len) { + l = min(sg_len, SBP2_MAX_SG_ELEMENT_LENGTH); + orb->page_table[j].low = sg_addr; + orb->page_table[j].high = (l << 16); + sg_addr += l; + sg_len -= l; + j++; + } + } + + size = sizeof(orb->page_table[0]) * j; + + /* + * The data_descriptor pointer is the one case where we need + * to fill in the node ID part of the address. All other + * pointers assume that the data referenced reside on the + * initiator (i.e. us), but data_descriptor can refer to data + * on other nodes so we need to put our ID in descriptor.high. + */ + + orb->page_table_bus = + dma_map_single(device->card->device, orb->page_table, + size, DMA_TO_DEVICE); + if (dma_mapping_error(orb->page_table_bus)) + goto fail_page_table; + orb->request.data_descriptor.high = sd->address_high; + orb->request.data_descriptor.low = orb->page_table_bus; + orb->request.misc |= + COMMAND_ORB_PAGE_TABLE_PRESENT | + COMMAND_ORB_DATA_SIZE(j); + + fw_memcpy_to_be32(orb->page_table, orb->page_table, size); + + return 0; + + fail_page_table: + dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg, + orb->cmd->sc_data_direction); + fail: + return -ENOMEM; +} + +/* SCSI stack integration */ + +static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) +{ + struct sbp2_device *sd = + (struct sbp2_device *)cmd->device->host->hostdata; + struct fw_unit *unit = sd->unit; + struct fw_device *device = fw_device(unit->device.parent); + struct sbp2_command_orb *orb; + + /* + * Bidirectional commands are not yet implemented, and unknown + * transfer direction not handled. + */ + if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) { + fw_error("Cannot handle DMA_BIDIRECTIONAL - rejecting command"); + cmd->result = DID_ERROR << 16; + done(cmd); + return 0; + } + + orb = kzalloc(sizeof(*orb), GFP_ATOMIC); + if (orb == NULL) { + fw_notify("failed to alloc orb\n"); + goto fail_alloc; + } + + /* Initialize rcode to something not RCODE_COMPLETE. */ + orb->base.rcode = -1; + orb->base.request_bus = + dma_map_single(device->card->device, &orb->request, + sizeof(orb->request), DMA_TO_DEVICE); + if (dma_mapping_error(orb->base.request_bus)) + goto fail_mapping; + + orb->unit = unit; + orb->done = done; + orb->cmd = cmd; + + orb->request.next.high = SBP2_ORB_NULL; + orb->request.next.low = 0x0; + /* + * At speed 100 we can do 512 bytes per packet, at speed 200, + * 1024 bytes per packet etc. The SBP-2 max_payload field + * specifies the max payload size as 2 ^ (max_payload + 2), so + * if we set this to max_speed + 7, we get the right value. + */ + orb->request.misc = + COMMAND_ORB_MAX_PAYLOAD(device->node->max_speed + 7) | + COMMAND_ORB_SPEED(device->node->max_speed) | + COMMAND_ORB_NOTIFY; + + if (cmd->sc_data_direction == DMA_FROM_DEVICE) + orb->request.misc |= + COMMAND_ORB_DIRECTION(SBP2_DIRECTION_FROM_MEDIA); + else if (cmd->sc_data_direction == DMA_TO_DEVICE) + orb->request.misc |= + COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA); + + if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0) + goto fail_map_payload; + + fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request)); + + memset(orb->request.command_block, + 0, sizeof(orb->request.command_block)); + memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd)); + + orb->base.callback = complete_command_orb; + + sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation, + sd->command_block_agent_address + SBP2_ORB_POINTER); + + return 0; + + fail_map_payload: + dma_unmap_single(device->card->device, orb->base.request_bus, + sizeof(orb->request), DMA_TO_DEVICE); + fail_mapping: + kfree(orb); + fail_alloc: + return SCSI_MLQUEUE_HOST_BUSY; +} + +static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) +{ + struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata; + + sdev->allow_restart = 1; + + if (sd->workarounds & SBP2_WORKAROUND_INQUIRY_36) + sdev->inquiry_len = 36; + return 0; +} + +static int sbp2_scsi_slave_configure(struct scsi_device *sdev) +{ + struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata; + struct fw_unit *unit = sd->unit; + + sdev->use_10_for_rw = 1; + + if (sdev->type == TYPE_ROM) + sdev->use_10_for_ms = 1; + if (sdev->type == TYPE_DISK && + sd->workarounds & SBP2_WORKAROUND_MODE_SENSE_8) + sdev->skip_ms_page_8 = 1; + if (sd->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) { + fw_notify("setting fix_capacity for %s\n", unit->device.bus_id); + sdev->fix_capacity = 1; + } + + return 0; +} + +/* + * Called by scsi stack when something has really gone wrong. Usually + * called when a command has timed-out for some reason. + */ +static int sbp2_scsi_abort(struct scsi_cmnd *cmd) +{ + struct sbp2_device *sd = + (struct sbp2_device *)cmd->device->host->hostdata; + struct fw_unit *unit = sd->unit; + + fw_notify("sbp2_scsi_abort\n"); + sbp2_agent_reset(unit); + sbp2_cancel_orbs(unit); + + return SUCCESS; +} + +static struct scsi_host_template scsi_driver_template = { + .module = THIS_MODULE, + .name = "SBP-2 IEEE-1394", + .proc_name = (char *)sbp2_driver_name, + .queuecommand = sbp2_scsi_queuecommand, + .slave_alloc = sbp2_scsi_slave_alloc, + .slave_configure = sbp2_scsi_slave_configure, + .eh_abort_handler = sbp2_scsi_abort, + .this_id = -1, + .sg_tablesize = SG_ALL, + .use_clustering = ENABLE_CLUSTERING, + .cmd_per_lun = 1, + .can_queue = 1, +}; + +MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); +MODULE_DESCRIPTION("SCSI over IEEE1394"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); + +/* Provide a module alias so root-on-sbp2 initrds don't break. */ +#ifndef CONFIG_IEEE1394_SBP2_MODULE +MODULE_ALIAS("sbp2"); +#endif + +static int __init sbp2_init(void) +{ + return driver_register(&sbp2_driver.driver); +} + +static void __exit sbp2_cleanup(void) +{ + driver_unregister(&sbp2_driver.driver); +} + +module_init(sbp2_init); +module_exit(sbp2_cleanup); diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c new file mode 100644 index 000000000000..7aebb8ae0efa --- /dev/null +++ b/drivers/firewire/fw-topology.c @@ -0,0 +1,537 @@ +/* + * Incremental bus scan, based on bus topology + * + * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/module.h> +#include <linux/wait.h> +#include <linux/errno.h> +#include "fw-transaction.h" +#include "fw-topology.h" + +#define SELF_ID_PHY_ID(q) (((q) >> 24) & 0x3f) +#define SELF_ID_EXTENDED(q) (((q) >> 23) & 0x01) +#define SELF_ID_LINK_ON(q) (((q) >> 22) & 0x01) +#define SELF_ID_GAP_COUNT(q) (((q) >> 16) & 0x3f) +#define SELF_ID_PHY_SPEED(q) (((q) >> 14) & 0x03) +#define SELF_ID_CONTENDER(q) (((q) >> 11) & 0x01) +#define SELF_ID_PHY_INITIATOR(q) (((q) >> 1) & 0x01) +#define SELF_ID_MORE_PACKETS(q) (((q) >> 0) & 0x01) + +#define SELF_ID_EXT_SEQUENCE(q) (((q) >> 20) & 0x07) + +static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count) +{ + u32 q; + int port_type, shift, seq; + + *total_port_count = 0; + *child_port_count = 0; + + shift = 6; + q = *sid; + seq = 0; + + while (1) { + port_type = (q >> shift) & 0x03; + switch (port_type) { + case SELFID_PORT_CHILD: + (*child_port_count)++; + case SELFID_PORT_PARENT: + case SELFID_PORT_NCONN: + (*total_port_count)++; + case SELFID_PORT_NONE: + break; + } + + shift -= 2; + if (shift == 0) { + if (!SELF_ID_MORE_PACKETS(q)) + return sid + 1; + + shift = 16; + sid++; + q = *sid; + + /* + * Check that the extra packets actually are + * extended self ID packets and that the + * sequence numbers in the extended self ID + * packets increase as expected. + */ + + if (!SELF_ID_EXTENDED(q) || + seq != SELF_ID_EXT_SEQUENCE(q)) + return NULL; + + seq++; + } + } +} + +static int get_port_type(u32 *sid, int port_index) +{ + int index, shift; + + index = (port_index + 5) / 8; + shift = 16 - ((port_index + 5) & 7) * 2; + return (sid[index] >> shift) & 0x03; +} + +static struct fw_node *fw_node_create(u32 sid, int port_count, int color) +{ + struct fw_node *node; + + node = kzalloc(sizeof(*node) + port_count * sizeof(node->ports[0]), + GFP_ATOMIC); + if (node == NULL) + return NULL; + + node->color = color; + node->node_id = LOCAL_BUS | SELF_ID_PHY_ID(sid); + node->link_on = SELF_ID_LINK_ON(sid); + node->phy_speed = SELF_ID_PHY_SPEED(sid); + node->port_count = port_count; + + atomic_set(&node->ref_count, 1); + INIT_LIST_HEAD(&node->link); + + return node; +} + +/* + * Compute the maximum hop count for this node and it's children. The + * maximum hop count is the maximum number of connections between any + * two nodes in the subtree rooted at this node. We need this for + * setting the gap count. As we build the tree bottom up in + * build_tree() below, this is fairly easy to do: for each node we + * maintain the max hop count and the max depth, ie the number of hops + * to the furthest leaf. Computing the max hop count breaks down into + * two cases: either the path goes through this node, in which case + * the hop count is the sum of the two biggest child depths plus 2. + * Or it could be the case that the max hop path is entirely + * containted in a child tree, in which case the max hop count is just + * the max hop count of this child. + */ +static void update_hop_count(struct fw_node *node) +{ + int depths[2] = { -1, -1 }; + int max_child_hops = 0; + int i; + + for (i = 0; i < node->port_count; i++) { + if (node->ports[i].node == NULL) + continue; + + if (node->ports[i].node->max_hops > max_child_hops) + max_child_hops = node->ports[i].node->max_hops; + + if (node->ports[i].node->max_depth > depths[0]) { + depths[1] = depths[0]; + depths[0] = node->ports[i].node->max_depth; + } else if (node->ports[i].node->max_depth > depths[1]) + depths[1] = node->ports[i].node->max_depth; + } + + node->max_depth = depths[0] + 1; + node->max_hops = max(max_child_hops, depths[0] + depths[1] + 2); +} + + +/** + * build_tree - Build the tree representation of the topology + * @self_ids: array of self IDs to create the tree from + * @self_id_count: the length of the self_ids array + * @local_id: the node ID of the local node + * + * This function builds the tree representation of the topology given + * by the self IDs from the latest bus reset. During the construction + * of the tree, the function checks that the self IDs are valid and + * internally consistent. On succcess this funtions returns the + * fw_node corresponding to the local card otherwise NULL. + */ +static struct fw_node *build_tree(struct fw_card *card, + u32 *sid, int self_id_count) +{ + struct fw_node *node, *child, *local_node, *irm_node; + struct list_head stack, *h; + u32 *next_sid, *end, q; + int i, port_count, child_port_count, phy_id, parent_count, stack_depth; + int gap_count, topology_type; + + local_node = NULL; + node = NULL; + INIT_LIST_HEAD(&stack); + stack_depth = 0; + end = sid + self_id_count; + phy_id = 0; + irm_node = NULL; + gap_count = SELF_ID_GAP_COUNT(*sid); + topology_type = 0; + + while (sid < end) { + next_sid = count_ports(sid, &port_count, &child_port_count); + + if (next_sid == NULL) { + fw_error("Inconsistent extended self IDs.\n"); + return NULL; + } + + q = *sid; + if (phy_id != SELF_ID_PHY_ID(q)) { + fw_error("PHY ID mismatch in self ID: %d != %d.\n", + phy_id, SELF_ID_PHY_ID(q)); + return NULL; + } + + if (child_port_count > stack_depth) { + fw_error("Topology stack underflow\n"); + return NULL; + } + + /* + * Seek back from the top of our stack to find the + * start of the child nodes for this node. + */ + for (i = 0, h = &stack; i < child_port_count; i++) + h = h->prev; + child = fw_node(h); + + node = fw_node_create(q, port_count, card->color); + if (node == NULL) { + fw_error("Out of memory while building topology."); + return NULL; + } + + if (phy_id == (card->node_id & 0x3f)) + local_node = node; + + if (SELF_ID_CONTENDER(q)) + irm_node = node; + + if (node->phy_speed == SCODE_BETA) + topology_type |= FW_TOPOLOGY_B; + else + topology_type |= FW_TOPOLOGY_A; + + parent_count = 0; + + for (i = 0; i < port_count; i++) { + switch (get_port_type(sid, i)) { + case SELFID_PORT_PARENT: + /* + * Who's your daddy? We dont know the + * parent node at this time, so we + * temporarily abuse node->color for + * remembering the entry in the + * node->ports array where the parent + * node should be. Later, when we + * handle the parent node, we fix up + * the reference. + */ + parent_count++; + node->color = i; + break; + + case SELFID_PORT_CHILD: + node->ports[i].node = child; + /* + * Fix up parent reference for this + * child node. + */ + child->ports[child->color].node = node; + child->color = card->color; + child = fw_node(child->link.next); + break; + } + } + + /* + * Check that the node reports exactly one parent + * port, except for the root, which of course should + * have no parents. + */ + if ((next_sid == end && parent_count != 0) || + (next_sid < end && parent_count != 1)) { + fw_error("Parent port inconsistency for node %d: " + "parent_count=%d\n", phy_id, parent_count); + return NULL; + } + + /* Pop the child nodes off the stack and push the new node. */ + __list_del(h->prev, &stack); + list_add_tail(&node->link, &stack); + stack_depth += 1 - child_port_count; + + /* + * If all PHYs does not report the same gap count + * setting, we fall back to 63 which will force a gap + * count reconfiguration and a reset. + */ + if (SELF_ID_GAP_COUNT(q) != gap_count) + gap_count = 63; + + update_hop_count(node); + + sid = next_sid; + phy_id++; + } + + card->root_node = node; + card->irm_node = irm_node; + card->gap_count = gap_count; + card->topology_type = topology_type; + + return local_node; +} + +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) +{ + struct list_head list; + struct fw_node *node, *next, *child, *parent; + int i; + + INIT_LIST_HEAD(&list); + + fw_node_get(root); + list_add_tail(&root->link, &list); + parent = NULL; + list_for_each_entry(node, &list, link) { + node->color = card->color; + + for (i = 0; i < node->port_count; i++) { + child = node->ports[i].node; + if (!child) + continue; + if (child->color == card->color) + parent = child; + else { + fw_node_get(child); + list_add_tail(&child->link, &list); + } + } + + callback(card, node, parent); + } + + list_for_each_entry_safe(node, next, &list, link) + fw_node_put(node); +} + +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); +} + +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); + + if (parent != NULL) { + /* min() macro doesn't work here with gcc 3.4 */ + node->max_speed = parent->max_speed < node->phy_speed ? + parent->max_speed : node->phy_speed; + node->b_path = parent->b_path && b_path; + } else { + node->max_speed = node->phy_speed; + node->b_path = b_path; + } + + fw_node_event(card, node, FW_NODE_CREATED); +} + +void fw_destroy_nodes(struct fw_card *card) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + card->color++; + if (card->local_node != NULL) + for_each_fw_node(card, card->local_node, report_lost_node); + spin_unlock_irqrestore(&card->lock, flags); +} + +static void move_tree(struct fw_node *node0, struct fw_node *node1, int port) +{ + struct fw_node *tree; + int i; + + tree = node1->ports[port].node; + node0->ports[port].node = tree; + for (i = 0; i < tree->port_count; i++) { + if (tree->ports[i].node == node1) { + tree->ports[i].node = node0; + break; + } + } +} + +/** + * update_tree - compare the old topology tree for card with the new + * one specified by root. Queue the nodes and mark them as either + * 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) +{ + struct list_head list0, list1; + struct fw_node *node0, *node1; + int i, event; + + INIT_LIST_HEAD(&list0); + list_add_tail(&card->local_node->link, &list0); + INIT_LIST_HEAD(&list1); + list_add_tail(&root->link, &list1); + + node0 = fw_node(list0.next); + node1 = fw_node(list1.next); + + while (&node0->link != &list0) { + + /* assert(node0->port_count == node1->port_count); */ + if (node0->link_on && !node1->link_on) + event = FW_NODE_LINK_OFF; + else if (!node0->link_on && node1->link_on) + event = FW_NODE_LINK_ON; + else + event = FW_NODE_UPDATED; + + node0->node_id = node1->node_id; + node0->color = card->color; + node0->link_on = node1->link_on; + node0->initiated_reset = node1->initiated_reset; + node0->max_hops = node1->max_hops; + node1->color = card->color; + fw_node_event(card, node0, event); + + if (card->root_node == node1) + card->root_node = node0; + if (card->irm_node == node1) + card->irm_node = node0; + + for (i = 0; i < node0->port_count; i++) { + if (node0->ports[i].node && node1->ports[i].node) { + /* + * This port didn't change, queue the + * connected node for further + * investigation. + */ + if (node0->ports[i].node->color == card->color) + continue; + list_add_tail(&node0->ports[i].node->link, + &list0); + list_add_tail(&node1->ports[i].node->link, + &list1); + } else if (node0->ports[i].node) { + /* + * The nodes connected here were + * unplugged; unref the lost nodes and + * queue FW_NODE_LOST callbacks for + * them. + */ + + for_each_fw_node(card, node0->ports[i].node, + report_lost_node); + node0->ports[i].node = NULL; + } else if (node1->ports[i].node) { + /* + * One or more node were connected to + * this port. Move the new nodes into + * the tree and queue FW_NODE_CREATED + * callbacks for them. + */ + move_tree(node0, node1, i); + for_each_fw_node(card, node0->ports[i].node, + report_found_node); + } + } + + node0 = fw_node(node0->link.next); + node1 = fw_node(node1->link.next); + } +} + +static void +update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count) +{ + int node_count; + + card->topology_map[1]++; + node_count = (card->root_node->node_id & 0x3f) + 1; + card->topology_map[2] = (node_count << 16) | self_id_count; + card->topology_map[0] = (self_id_count + 2) << 16; + memcpy(&card->topology_map[3], self_ids, self_id_count * 4); + 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) +{ + struct fw_node *local_node; + unsigned long flags; + + fw_flush_transactions(card); + + spin_lock_irqsave(&card->lock, flags); + + /* + * If the new topology has a different self_id_count the topology + * changed, either nodes were added or removed. In that case we + * reset the IRM reset counter. + */ + if (card->self_id_count != self_id_count) + card->bm_retries = 0; + + card->node_id = node_id; + card->generation = generation; + card->reset_jiffies = jiffies; + schedule_delayed_work(&card->work, 0); + + local_node = build_tree(card, self_ids, self_id_count); + + update_topology_map(card, self_ids, self_id_count); + + card->color++; + + if (local_node == NULL) { + fw_error("topology build failed\n"); + /* FIXME: We need to issue a bus reset in this case. */ + } else if (card->local_node == NULL) { + card->local_node = local_node; + for_each_fw_node(card, local_node, report_found_node); + } else { + update_tree(card, local_node); + } + + spin_unlock_irqrestore(&card->lock, flags); +} +EXPORT_SYMBOL(fw_core_handle_bus_reset); diff --git a/drivers/firewire/fw-topology.h b/drivers/firewire/fw-topology.h new file mode 100644 index 000000000000..363b6cbcd0b3 --- /dev/null +++ b/drivers/firewire/fw-topology.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __fw_topology_h +#define __fw_topology_h + +enum { + FW_TOPOLOGY_A = 0x01, + FW_TOPOLOGY_B = 0x02, + FW_TOPOLOGY_MIXED = 0x03, +}; + +enum { + FW_NODE_CREATED = 0x00, + FW_NODE_UPDATED = 0x01, + FW_NODE_DESTROYED = 0x02, + FW_NODE_LINK_ON = 0x03, + FW_NODE_LINK_OFF = 0x04, +}; + +struct fw_port { + struct fw_node *node; + unsigned speed : 3; /* S100, S200, ... S3200 */ +}; + +struct fw_node { + u16 node_id; + u8 color; + u8 port_count; + unsigned link_on : 1; + unsigned initiated_reset : 1; + unsigned b_path : 1; + u8 phy_speed : 3; /* As in the self ID packet. */ + u8 max_speed : 5; /* Minimum of all phy-speeds and port speeds on + * the path from the local node to this node. */ + u8 max_depth : 4; /* Maximum depth to any leaf node */ + u8 max_hops : 4; /* Max hops in this sub tree */ + atomic_t ref_count; + + /* For serializing node topology into a list. */ + struct list_head link; + + /* Upper layer specific data. */ + void *data; + + struct fw_port ports[0]; +}; + +static inline struct fw_node * +fw_node(struct list_head *l) +{ + return list_entry(l, struct fw_node, link); +} + +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) +{ + 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); + + +#endif /* __fw_topology_h */ diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c new file mode 100644 index 000000000000..80d0121463d0 --- /dev/null +++ b/drivers/firewire/fw-transaction.c @@ -0,0 +1,910 @@ +/* + * Core IEEE1394 transaction logic + * + * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/poll.h> +#include <linux/list.h> +#include <linux/kthread.h> +#include <asm/uaccess.h> +#include <asm/semaphore.h> + +#include "fw-transaction.h" +#include "fw-topology.h" +#include "fw-device.h" + +#define HEADER_PRI(pri) ((pri) << 0) +#define HEADER_TCODE(tcode) ((tcode) << 4) +#define HEADER_RETRY(retry) ((retry) << 8) +#define HEADER_TLABEL(tlabel) ((tlabel) << 10) +#define HEADER_DESTINATION(destination) ((destination) << 16) +#define HEADER_SOURCE(source) ((source) << 16) +#define HEADER_RCODE(rcode) ((rcode) << 12) +#define HEADER_OFFSET_HIGH(offset_high) ((offset_high) << 0) +#define HEADER_DATA_LENGTH(length) ((length) << 16) +#define HEADER_EXTENDED_TCODE(tcode) ((tcode) << 0) + +#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f) +#define HEADER_GET_TLABEL(q) (((q) >> 10) & 0x3f) +#define HEADER_GET_RCODE(q) (((q) >> 12) & 0x0f) +#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff) +#define HEADER_GET_SOURCE(q) (((q) >> 16) & 0xffff) +#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff) +#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) +#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) + +#define PHY_CONFIG_GAP_COUNT(gap_count) (((gap_count) << 16) | (1 << 22)) +#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) +{ + struct fw_transaction *t; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + list_for_each_entry(t, &card->transaction_list, link) { + if (t == transaction) { + list_del(&t->link); + card->tlabel_mask &= ~(1 << t->tlabel); + break; + } + } + spin_unlock_irqrestore(&card->lock, flags); + + if (&t->link != &card->transaction_list) { + t->callback(card, rcode, payload, length, t->callback_data); + return 0; + } + + return -ENOENT; +} + +/* + * Only valid for transactions that are potentially pending (ie have + * been sent). + */ +int +fw_cancel_transaction(struct fw_card *card, + struct fw_transaction *transaction) +{ + /* + * Cancel the packet transmission if it's still queued. That + * will call the packet transmission callback which cancels + * the transaction. + */ + + if (card->driver->cancel_packet(card, &transaction->packet) == 0) + return 0; + + /* + * If the request packet has already been sent, we need to see + * if the transaction is still pending and remove it in that case. + */ + + return close_transaction(transaction, card, RCODE_CANCELLED, NULL, 0); +} +EXPORT_SYMBOL(fw_cancel_transaction); + +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); + break; + case ACK_PENDING: + t->timestamp = packet->timestamp; + break; + case ACK_BUSY_X: + case ACK_BUSY_A: + case ACK_BUSY_B: + close_transaction(t, card, RCODE_BUSY, NULL, 0); + break; + case ACK_DATA_ERROR: + close_transaction(t, card, RCODE_DATA_ERROR, NULL, 0); + break; + case ACK_TYPE_ERROR: + close_transaction(t, card, RCODE_TYPE_ERROR, NULL, 0); + 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); + break; + } +} + +static void +fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, + int node_id, int source_id, int generation, int speed, + unsigned long long offset, void *payload, size_t length) +{ + int ext_tcode; + + if (tcode > 0x10) { + ext_tcode = tcode - 0x10; + tcode = TCODE_LOCK_REQUEST; + } else + ext_tcode = 0; + + packet->header[0] = + HEADER_RETRY(RETRY_X) | + HEADER_TLABEL(tlabel) | + HEADER_TCODE(tcode) | + HEADER_DESTINATION(node_id); + packet->header[1] = + HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); + packet->header[2] = + offset; + + switch (tcode) { + case TCODE_WRITE_QUADLET_REQUEST: + packet->header[3] = *(u32 *)payload; + packet->header_length = 16; + packet->payload_length = 0; + break; + + case TCODE_LOCK_REQUEST: + case TCODE_WRITE_BLOCK_REQUEST: + packet->header[3] = + HEADER_DATA_LENGTH(length) | + HEADER_EXTENDED_TCODE(ext_tcode); + packet->header_length = 16; + packet->payload = payload; + packet->payload_length = length; + break; + + case TCODE_READ_QUADLET_REQUEST: + packet->header_length = 12; + packet->payload_length = 0; + break; + + case TCODE_READ_BLOCK_REQUEST: + packet->header[3] = + HEADER_DATA_LENGTH(length) | + HEADER_EXTENDED_TCODE(ext_tcode); + packet->header_length = 16; + packet->payload_length = 0; + break; + } + + packet->speed = speed; + packet->generation = generation; + packet->ack = 0; +} + +/** + * This function provides low-level access to the IEEE1394 transaction + * logic. Most C programs would use either fw_read(), fw_write() or + * fw_lock() instead - those function are convenience wrappers for + * this function. The fw_send_request() function is primarily + * provided as a flexible, one-stop entry point for languages bindings + * and protocol bindings. + * + * FIXME: Document this function further, in particular the possible + * values for rcode in the callback. In short, we map ACK_COMPLETE to + * RCODE_COMPLETE, internal errors set errno and set rcode to + * RCODE_SEND_ERROR (which is out of range for standard ieee1394 + * rcodes). All other rcodes are forwarded unchanged. For all + * errors, payload is NULL, length is 0. + * + * Can not expect the callback to be called before the function + * returns, though this does happen in some cases (ACK_COMPLETE and + * errors). + * + * The payload is only used for write requests and must not be freed + * until the callback has been called. + * + * @param card the card from which to send the request + * @param tcode the tcode for this transaction. Do not use + * TCODE_LOCK_REQUEST directly, insted use TCODE_LOCK_MASK_SWAP + * etc. to specify tcode and ext_tcode. + * @param node_id the destination node ID (bus ID and PHY ID concatenated) + * @param generation the generation for which node_id is valid + * @param speed the speed to use for sending the request + * @param offset the 48 bit offset on the destination node + * @param payload the data payload for the request subaction + * @param length the length in bytes of the data to read + * @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 + */ +void +fw_send_request(struct fw_card *card, struct fw_transaction *t, + int tcode, int node_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, source; + + /* + * Bump the flush timer up 100ms first of all so we + * don't race with a flush timer callback. + */ + + mod_timer(&card->flush_timer, jiffies + DIV_ROUND_UP(HZ, 10)); + + /* + * Allocate tlabel from the bitmap and put the transaction on + * the list while holding the card spinlock. + */ + + spin_lock_irqsave(&card->lock, flags); + + source = card->node_id; + tlabel = card->current_tlabel; + if (card->tlabel_mask & (1 << tlabel)) { + spin_unlock_irqrestore(&card->lock, flags); + callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data); + return; + } + + card->current_tlabel = (card->current_tlabel + 1) & 0x1f; + card->tlabel_mask |= (1 << tlabel); + + list_add_tail(&t->link, &card->transaction_list); + + spin_unlock_irqrestore(&card->lock, flags); + + /* Initialize rest of transaction, fill out packet and send it. */ + t->node_id = node_id; + t->tlabel = tlabel; + t->callback = callback; + t->callback_data = callback_data; + + fw_fill_request(&t->packet, tcode, t->tlabel, + node_id, source, generation, + speed, offset, payload, length); + t->packet.callback = transmit_complete_callback; + + card->driver->send_request(card, &t->packet); +} +EXPORT_SYMBOL(fw_send_request); + +static void +transmit_phy_packet_callback(struct fw_packet *packet, + struct fw_card *card, int status) +{ + kfree(packet); +} + +static void send_phy_packet(struct fw_card *card, u32 data, int generation) +{ + struct fw_packet *packet; + + packet = kzalloc(sizeof(*packet), GFP_ATOMIC); + if (packet == NULL) + return; + + packet->header[0] = data; + packet->header[1] = ~data; + packet->header_length = 8; + packet->payload_length = 0; + packet->speed = SCODE_100; + packet->generation = generation; + packet->callback = transmit_phy_packet_callback; + + card->driver->send_request(card, packet); +} + +void fw_send_phy_config(struct fw_card *card, + int node_id, int generation, int gap_count) +{ + u32 q; + + q = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | + PHY_CONFIG_ROOT_ID(node_id) | + PHY_CONFIG_GAP_COUNT(gap_count); + + send_phy_packet(card, q, generation); +} + +void fw_flush_transactions(struct fw_card *card) +{ + struct fw_transaction *t, *next; + struct list_head list; + unsigned long flags; + + INIT_LIST_HEAD(&list); + spin_lock_irqsave(&card->lock, flags); + list_splice_init(&card->transaction_list, &list); + card->tlabel_mask = 0; + spin_unlock_irqrestore(&card->lock, flags); + + list_for_each_entry_safe(t, next, &list, link) { + card->driver->cancel_packet(card, &t->packet); + + /* + * At this point cancel_packet will never call the + * transaction callback, since we just took all the + * transactions out of the list. So do it here. + */ + t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); + } +} + +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; + + list_for_each_entry(handler, list, link) { + if (handler->offset < offset + length && + offset < handler->offset + handler->length) + return handler; + } + + return NULL; +} + +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; + + list_for_each_entry(handler, list, link) { + if (handler->offset <= offset && + offset + length <= handler->offset + handler->length) + return handler; + } + + return NULL; +} + +static DEFINE_SPINLOCK(address_handler_lock); +static LIST_HEAD(address_handler_list); + +const struct fw_address_region fw_low_memory_region = + { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; +const struct fw_address_region fw_high_memory_region = + { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, }; +const struct fw_address_region fw_private_region = + { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, }; +const struct fw_address_region fw_csr_region = + { .start = 0xfffff0000000ULL, .end = 0xfffff0000800ULL, }; +const struct fw_address_region fw_unit_space_region = + { .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, }; +EXPORT_SYMBOL(fw_low_memory_region); +EXPORT_SYMBOL(fw_high_memory_region); +EXPORT_SYMBOL(fw_private_region); +EXPORT_SYMBOL(fw_csr_region); +EXPORT_SYMBOL(fw_unit_space_region); + +/** + * 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 + */ +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; + + spin_lock_irqsave(&address_handler_lock, flags); + + 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 += other->length; + } else { + list_add_tail(&handler->link, &address_handler_list); + ret = 0; + break; + } + } + + spin_unlock_irqrestore(&address_handler_lock, flags); + + return ret; +} +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. + */ +void fw_core_remove_address_handler(struct fw_address_handler *handler) +{ + unsigned long flags; + + spin_lock_irqsave(&address_handler_lock, flags); + list_del(&handler->link); + spin_unlock_irqrestore(&address_handler_lock, flags); +} +EXPORT_SYMBOL(fw_core_remove_address_handler); + +struct fw_request { + struct fw_packet response; + u32 request_header[4]; + int ack; + u32 length; + u32 data[0]; +}; + +static void +free_response_callback(struct fw_packet *packet, + struct fw_card *card, int status) +{ + struct fw_request *request; + + request = container_of(packet, struct fw_request, response); + kfree(request); +} + +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; + + tcode = HEADER_GET_TCODE(request_header[0]); + tlabel = HEADER_GET_TLABEL(request_header[0]); + source = HEADER_GET_DESTINATION(request_header[0]); + destination = HEADER_GET_SOURCE(request_header[1]); + extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]); + + response->header[0] = + HEADER_RETRY(RETRY_1) | + HEADER_TLABEL(tlabel) | + HEADER_DESTINATION(destination); + response->header[1] = + HEADER_SOURCE(source) | + HEADER_RCODE(rcode); + response->header[2] = 0; + + switch (tcode) { + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_WRITE_BLOCK_REQUEST: + response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE); + response->header_length = 12; + response->payload_length = 0; + break; + + case TCODE_READ_QUADLET_REQUEST: + response->header[0] |= + HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE); + if (payload != NULL) + response->header[3] = *(u32 *)payload; + else + response->header[3] = 0; + response->header_length = 16; + response->payload_length = 0; + break; + + case TCODE_READ_BLOCK_REQUEST: + case TCODE_LOCK_REQUEST: + response->header[0] |= HEADER_TCODE(tcode + 2); + response->header[3] = + HEADER_DATA_LENGTH(length) | + HEADER_EXTENDED_TCODE(extended_tcode); + response->header_length = 16; + response->payload = payload; + response->payload_length = length; + break; + + default: + BUG(); + return; + } +} +EXPORT_SYMBOL(fw_fill_response); + +static struct fw_request * +allocate_request(struct fw_packet *p) +{ + struct fw_request *request; + u32 *data, length; + int request_tcode, t; + + request_tcode = HEADER_GET_TCODE(p->header[0]); + switch (request_tcode) { + case TCODE_WRITE_QUADLET_REQUEST: + data = &p->header[3]; + length = 4; + break; + + case TCODE_WRITE_BLOCK_REQUEST: + case TCODE_LOCK_REQUEST: + data = p->payload; + length = HEADER_GET_DATA_LENGTH(p->header[3]); + break; + + case TCODE_READ_QUADLET_REQUEST: + data = NULL; + length = 4; + break; + + case TCODE_READ_BLOCK_REQUEST: + data = NULL; + length = HEADER_GET_DATA_LENGTH(p->header[3]); + break; + + default: + BUG(); + return NULL; + } + + request = kmalloc(sizeof(*request) + length, GFP_ATOMIC); + if (request == NULL) + return NULL; + + t = (p->timestamp & 0x1fff) + 4000; + if (t >= 8000) + t = (p->timestamp & ~0x1fff) + 0x2000 + t - 8000; + else + t = (p->timestamp & ~0x1fff) + t; + + request->response.speed = p->speed; + request->response.timestamp = t; + request->response.generation = p->generation; + request->response.ack = 0; + request->response.callback = free_response_callback; + request->ack = p->ack; + request->length = length; + if (data) + memcpy(request->data, data, length); + + memcpy(request->request_header, p->header, sizeof(p->header)); + + return request; +} + +void +fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) +{ + /* + * Broadcast packets are reported as ACK_COMPLETE, so this + * check is sufficient to ensure we don't send response to + * broadcast packets or posted writes. + */ + if (request->ack != ACK_PENDING) + return; + + if (rcode == RCODE_COMPLETE) + fw_fill_response(&request->response, request->request_header, + rcode, request->data, request->length); + else + fw_fill_response(&request->response, request->request_header, + rcode, NULL, 0); + + card->driver->send_response(card, &request->response); +} +EXPORT_SYMBOL(fw_send_response); + +void +fw_core_handle_request(struct fw_card *card, struct fw_packet *p) +{ + struct fw_address_handler *handler; + struct fw_request *request; + unsigned long long offset; + unsigned long flags; + int tcode, destination, source; + + if (p->payload_length > 2048) { + /* FIXME: send error response. */ + return; + } + + if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) + return; + + request = allocate_request(p); + if (request == NULL) { + /* FIXME: send statically allocated busy packet. */ + return; + } + + offset = + ((unsigned long long) + HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | p->header[2]; + tcode = HEADER_GET_TCODE(p->header[0]); + destination = HEADER_GET_DESTINATION(p->header[0]); + source = HEADER_GET_SOURCE(p->header[0]); + + spin_lock_irqsave(&address_handler_lock, flags); + handler = lookup_enclosing_address_handler(&address_handler_list, + offset, request->length); + spin_unlock_irqrestore(&address_handler_lock, flags); + + /* + * FIXME: lookup the fw_node corresponding to the sender of + * this request and pass that to the address handler instead + * of the node ID. We may also want to move the address + * allocations to fw_node so we only do this callback if the + * upper layers registered it for this node. + */ + + if (handler == NULL) + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + else + handler->address_callback(card, request, + tcode, destination, source, + p->generation, p->speed, offset, + request->data, request->length, + handler->callback_data); +} +EXPORT_SYMBOL(fw_core_handle_request); + +void +fw_core_handle_response(struct fw_card *card, struct fw_packet *p) +{ + struct fw_transaction *t; + unsigned long flags; + u32 *data; + size_t data_length; + int tcode, tlabel, destination, source, rcode; + + tcode = HEADER_GET_TCODE(p->header[0]); + tlabel = HEADER_GET_TLABEL(p->header[0]); + destination = HEADER_GET_DESTINATION(p->header[0]); + source = HEADER_GET_SOURCE(p->header[1]); + rcode = HEADER_GET_RCODE(p->header[1]); + + spin_lock_irqsave(&card->lock, flags); + list_for_each_entry(t, &card->transaction_list, link) { + if (t->node_id == source && t->tlabel == tlabel) { + list_del(&t->link); + card->tlabel_mask &= ~(1 << t->tlabel); + break; + } + } + spin_unlock_irqrestore(&card->lock, flags); + + if (&t->link == &card->transaction_list) { + fw_notify("Unsolicited response (source %x, tlabel %x)\n", + source, tlabel); + return; + } + + /* + * FIXME: sanity check packet, is length correct, does tcodes + * and addresses match. + */ + + switch (tcode) { + case TCODE_READ_QUADLET_RESPONSE: + data = (u32 *) &p->header[3]; + data_length = 4; + break; + + case TCODE_WRITE_RESPONSE: + data = NULL; + data_length = 0; + break; + + case TCODE_READ_BLOCK_RESPONSE: + case TCODE_LOCK_RESPONSE: + data = p->payload; + data_length = HEADER_GET_DATA_LENGTH(p->header[3]); + break; + + default: + /* Should never happen, this is just to shut up gcc. */ + data = NULL; + data_length = 0; + break; + } + + t->callback(card, rcode, data, data_length, t->callback_data); +} +EXPORT_SYMBOL(fw_core_handle_response); + +const struct fw_address_region topology_map_region = + { .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, }; + +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; + u32 *map; + + if (!TCODE_IS_READ_REQUEST(tcode)) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + return; + } + + if ((offset & 3) > 0 || (length & 3) > 0) { + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + return; + } + + start = (offset - topology_map_region.start) / 4; + end = start + length / 4; + map = payload; + + for (i = 0; i < length / 4; i++) + map[i] = cpu_to_be32(card->topology_map[start + i]); + + fw_send_response(card, request, RCODE_COMPLETE); +} + +static struct fw_address_handler topology_map = { + .length = 0x200, + .address_callback = handle_topology_map, +}; + +const struct fw_address_region registers_region = + { .start = 0xfffff0000000ull, .end = 0xfffff0000400ull, }; + +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; + __be32 *data = payload; + + switch (reg) { + case CSR_CYCLE_TIME: + case CSR_BUS_TIME: + if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + break; + } + + bus_time = card->driver->get_bus_time(card); + if (reg == CSR_CYCLE_TIME) + *data = cpu_to_be32(bus_time); + else + *data = cpu_to_be32(bus_time >> 25); + fw_send_response(card, request, RCODE_COMPLETE); + break; + + case CSR_BUS_MANAGER_ID: + case CSR_BANDWIDTH_AVAILABLE: + case CSR_CHANNELS_AVAILABLE_HI: + case CSR_CHANNELS_AVAILABLE_LO: + /* + * FIXME: these are handled by the OHCI hardware and + * the stack never sees these request. If we add + * support for a new type of controller that doesn't + * handle this in hardware we need to deal with these + * transactions. + */ + BUG(); + break; + + case CSR_BUSY_TIMEOUT: + /* FIXME: Implement this. */ + default: + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + break; + } +} + +static struct fw_address_handler registers = { + .length = 0x400, + .address_callback = handle_registers, +}; + +MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); +MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); +MODULE_LICENSE("GPL"); + +static const u32 vendor_textual_descriptor[] = { + /* textual descriptor leaf () */ + 0x00060000, + 0x00000000, + 0x00000000, + 0x4c696e75, /* L i n u */ + 0x78204669, /* x F i */ + 0x72657769, /* r e w i */ + 0x72650000, /* r e */ +}; + +static const u32 model_textual_descriptor[] = { + /* model descriptor leaf () */ + 0x00030000, + 0x00000000, + 0x00000000, + 0x4a756a75, /* J u j u */ +}; + +static struct fw_descriptor vendor_id_descriptor = { + .length = ARRAY_SIZE(vendor_textual_descriptor), + .immediate = 0x03d00d1e, + .key = 0x81000000, + .data = vendor_textual_descriptor, +}; + +static struct fw_descriptor model_id_descriptor = { + .length = ARRAY_SIZE(model_textual_descriptor), + .immediate = 0x17000001, + .key = 0x81000000, + .data = model_textual_descriptor, +}; + +static int __init fw_core_init(void) +{ + int retval; + + retval = bus_register(&fw_bus_type); + if (retval < 0) + return retval; + + fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); + if (fw_cdev_major < 0) { + bus_unregister(&fw_bus_type); + 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(®isters, + ®isters_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); + + return 0; +} + +static void __exit fw_core_cleanup(void) +{ + unregister_chrdev(fw_cdev_major, "firewire"); + bus_unregister(&fw_bus_type); +} + +module_init(fw_core_init); +module_exit(fw_core_cleanup); diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h new file mode 100644 index 000000000000..acdc3be38c61 --- /dev/null +++ b/drivers/firewire/fw-transaction.h @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __fw_transaction_h +#define __fw_transaction_h + +#include <linux/device.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/fs.h> +#include <linux/dma-mapping.h> +#include <linux/firewire-constants.h> + +#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) +#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) +#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) +#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) +#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4) +#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0) + +#define LOCAL_BUS 0xffc0 + +#define SELFID_PORT_CHILD 0x3 +#define SELFID_PORT_PARENT 0x2 +#define SELFID_PORT_NCONN 0x1 +#define SELFID_PORT_NONE 0x0 + +#define PHY_PACKET_CONFIG 0x0 +#define PHY_PACKET_LINK_ON 0x1 +#define PHY_PACKET_SELF_ID 0x2 + +/* Bit fields _within_ the PHY registers. */ +#define PHY_LINK_ACTIVE 0x80 +#define PHY_CONTENDER 0x40 +#define PHY_BUS_RESET 0x40 +#define PHY_BUS_SHORT_RESET 0x40 + +#define CSR_REGISTER_BASE 0xfffff0000000ULL + +/* register offsets relative to CSR_REGISTER_BASE */ +#define CSR_STATE_CLEAR 0x0 +#define CSR_STATE_SET 0x4 +#define CSR_NODE_IDS 0x8 +#define CSR_RESET_START 0xc +#define CSR_SPLIT_TIMEOUT_HI 0x18 +#define CSR_SPLIT_TIMEOUT_LO 0x1c +#define CSR_CYCLE_TIME 0x200 +#define CSR_BUS_TIME 0x204 +#define CSR_BUSY_TIMEOUT 0x210 +#define CSR_BUS_MANAGER_ID 0x21c +#define CSR_BANDWIDTH_AVAILABLE 0x220 +#define CSR_CHANNELS_AVAILABLE 0x224 +#define CSR_CHANNELS_AVAILABLE_HI 0x224 +#define CSR_CHANNELS_AVAILABLE_LO 0x228 +#define CSR_BROADCAST_CHANNEL 0x234 +#define CSR_CONFIG_ROM 0x400 +#define CSR_CONFIG_ROM_END 0x800 +#define CSR_FCP_COMMAND 0xB00 +#define CSR_FCP_RESPONSE 0xD00 +#define CSR_FCP_END 0xF00 +#define CSR_TOPOLOGY_MAP 0x1000 +#define CSR_TOPOLOGY_MAP_END 0x1400 +#define CSR_SPEED_MAP 0x2000 +#define CSR_SPEED_MAP_END 0x3000 + +#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args) +#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) +#define fw_debug(s, args...) printk(KERN_DEBUG KBUILD_MODNAME ": " s, ## args) + +static inline void +fw_memcpy_from_be32(void *_dst, void *_src, size_t size) +{ + u32 *dst = _dst; + u32 *src = _src; + int i; + + for (i = 0; i < size / 4; i++) + dst[i] = cpu_to_be32(src[i]); +} + +static inline void +fw_memcpy_to_be32(void *_dst, void *_src, size_t size) +{ + fw_memcpy_from_be32(_dst, _src, size); +} + +struct fw_card; +struct fw_packet; +struct fw_node; +struct fw_request; + +struct fw_descriptor { + struct list_head link; + size_t length; + u32 immediate; + u32 key; + const u32 *data; +}; + +int fw_core_add_descriptor(struct fw_descriptor *desc); +void fw_core_remove_descriptor(struct fw_descriptor *desc); + +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 *callback_data); + +typedef void (*fw_address_callback_t)(struct fw_card *card, + struct fw_request *request, + int tcode, int destination, int source, + int generation, int speed, + unsigned long long offset, + 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; + u32 header[4]; + size_t header_length; + void *payload; + size_t payload_length; + u32 timestamp; + + /* + * This callback is called when the packet transmission has + * completed; for successful transmission, the status code is + * the ack received from the destination, otherwise it's a + * negative errno: ENOMEM, ESTALE, ETIMEDOUT, ENODEV, EIO. + * The callback can be called from tasklet context and thus + * must never block. + */ + fw_packet_callback_t callback; + int ack; + struct list_head link; + void *driver_data; +}; + +struct fw_transaction { + int node_id; /* The generation is implied; it is always the current. */ + int tlabel; + int timestamp; + struct list_head link; + + struct fw_packet packet; + + /* + * The data passed to the callback is valid only during the + * callback. + */ + fw_transaction_callback_t callback; + 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; + fw_address_callback_t address_callback; + void *callback_data; + struct list_head link; +}; + + +struct fw_address_region { + u64 start; + u64 end; +}; + +extern const struct fw_address_region fw_low_memory_region; +extern const struct fw_address_region fw_high_memory_region; +extern const struct fw_address_region fw_private_region; +extern const struct fw_address_region fw_csr_region; +extern const struct fw_address_region fw_unit_space_region; + +int fw_core_add_address_handler(struct fw_address_handler *handler, + const struct fw_address_region *region); +void fw_core_remove_address_handler(struct fw_address_handler *handler); +void fw_fill_response(struct fw_packet *response, u32 *request_header, + int rcode, void *payload, size_t length); +void fw_send_response(struct fw_card *card, + struct fw_request *request, int rcode); + +extern struct bus_type fw_bus_type; + +struct fw_card { + const struct fw_card_driver *driver; + struct device *device; + struct kref kref; + + int node_id; + int generation; + /* This is the generation used for timestamping incoming requests. */ + int request_generation; + int current_tlabel, tlabel_mask; + struct list_head transaction_list; + struct timer_list flush_timer; + unsigned long reset_jiffies; + + unsigned long long guid; + int max_receive; + int link_speed; + int config_rom_generation; + + /* + * We need to store up to 4 self ID for a maximum of 63 + * devices plus 3 words for the topology map header. + */ + int self_id_count; + u32 topology_map[252 + 3]; + + spinlock_t lock; /* Take this lock when handling the lists in + * this struct. */ + struct fw_node *local_node; + struct fw_node *root_node; + struct fw_node *irm_node; + int color; + int gap_count; + int topology_type; + + int index; + + struct list_head link; + + /* Work struct for BM duties. */ + struct delayed_work work; + int bm_retries; + int bm_generation; +}; + +struct fw_card *fw_card_get(struct fw_card *card); +void fw_card_put(struct fw_card *card); + +/* + * The iso packet format allows for an immediate header/payload part + * stored in 'header' immediately after the packet info plus an + * indirect payload part that is pointer to by the 'payload' field. + * Applications can use one or the other or both to implement simple + * low-bandwidth streaming (e.g. audio) or more advanced + * scatter-gather streaming (e.g. assembling video frame automatically). + */ + +struct fw_iso_packet { + u16 payload_length; /* Length of indirect payload. */ + u32 interrupt : 1; /* Generate interrupt on this packet */ + u32 skip : 1; /* Set to not send packet at all. */ + u32 tag : 2; + u32 sy : 4; + u32 header_length : 8; /* Length of immediate header. */ + u32 header[0]; +}; + +#define FW_ISO_CONTEXT_TRANSMIT 0 +#define FW_ISO_CONTEXT_RECEIVE 1 + +#define FW_ISO_CONTEXT_MATCH_TAG0 1 +#define FW_ISO_CONTEXT_MATCH_TAG1 2 +#define FW_ISO_CONTEXT_MATCH_TAG2 4 +#define FW_ISO_CONTEXT_MATCH_TAG3 8 +#define FW_ISO_CONTEXT_MATCH_ALL_TAGS 15 + +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); + +/* + * An iso buffer is just a set of pages mapped for DMA in the + * specified direction. Since the pages are to be used for DMA, they + * are not mapped into the kernel virtual address space. We store the + * DMA address in the page private. The helper function + * fw_iso_buffer_map() will map the pages into a given vma. + */ + +struct fw_iso_buffer { + enum dma_data_direction direction; + struct page **pages; + int page_count; +}; + +struct fw_iso_context { + 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_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); + +struct fw_card_driver { + const char *name; + + /* + * Enable the given card with the given initial config rom. + * This function is expected to activate the card, and either + * enable the PHY or set the link_on bit and initiate a bus + * reset. + */ + int (*enable)(struct fw_card *card, u32 *config_rom, size_t length); + + int (*update_phy_reg)(struct fw_card *card, int address, + int clear_bits, int set_bits); + + /* + * Update the config rom for an enabled card. This function + * should change the config rom that is presented on the bus + * an initiate a bus reset. + */ + int (*set_config_rom)(struct fw_card *card, + u32 *config_rom, size_t length); + + void (*send_request)(struct fw_card *card, struct fw_packet *packet); + void (*send_response)(struct fw_card *card, struct fw_packet *packet); + /* Calling cancel is valid once a packet has been submitted. */ + int (*cancel_packet)(struct fw_card *card, struct fw_packet *packet); + + /* + * Allow the specified node ID to do direct DMA out and in of + * host memory. The card will disable this for all node when + * a bus reset happens, so driver need to reenable this after + * bus reset. Returns 0 on success, -ENODEV if the card + * doesn't support this, -ESTALE if the generation doesn't + * match. + */ + int (*enable_phys_dma)(struct fw_card *card, + int node_id, int generation); + + u64 (*get_bus_time)(struct fw_card *card); + + struct fw_iso_context * + (*allocate_iso_context)(struct fw_card *card, + int type, size_t header_size); + void (*free_iso_context)(struct fw_iso_context *ctx); + + int (*start_iso)(struct fw_iso_context *ctx, + s32 cycle, u32 sync, u32 tags); + + int (*queue_iso)(struct fw_iso_context *ctx, + struct fw_iso_packet *packet, + struct fw_iso_buffer *buffer, + unsigned long payload); + + int (*stop_iso)(struct fw_iso_context *ctx); +}; + +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, + int tcode, int node_id, int generation, int speed, + unsigned long long offset, + void *data, size_t length, + fw_transaction_callback_t callback, void *callback_data); + +int fw_cancel_transaction(struct fw_card *card, + struct fw_transaction *transaction); + +void fw_flush_transactions(struct fw_card *card); + +void fw_send_phy_config(struct fw_card *card, + int node_id, int generation, int gap_count); + +/* + * Called by the topology code to inform the device code of node + * activity; found, lost, or updated nodes. + */ +void +fw_node_event(struct fw_card *card, struct fw_node *node, int event); + +/* API used by card level drivers */ + +void +fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver, + struct device *device); +int +fw_card_add(struct fw_card *card, + u32 max_receive, u32 link_speed, u64 guid); + +void +fw_core_remove_card(struct fw_card *card); + +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_request(struct fw_card *card, struct fw_packet *request); + +void +fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); + +#endif /* __fw_transaction_h */ diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 3ba3a5221c41..4d1cb5b855d1 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -4,6 +4,7 @@ menuconfig HWMON tristate "Hardware Monitoring support" + depends on HAS_IOMEM default y help Hardware monitoring devices let you monitor the hardware health diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c index 18210164e307..ca7095d96ad0 100644 --- a/drivers/hwmon/ams/ams-input.c +++ b/drivers/hwmon/ams/ams-input.c @@ -87,7 +87,7 @@ static void ams_input_enable(void) ams_info.idev->id.vendor = 0; ams_info.idev->open = ams_input_open; ams_info.idev->close = ams_input_close; - ams_info.idev->cdev.dev = &ams_info.of_dev->dev; + ams_info.idev->dev.parent = &ams_info.of_dev->dev; input_set_abs_params(ams_info.idev, ABS_X, -50, 50, 3, 0); input_set_abs_params(ams_info.idev, ABS_Y, -50, 50, 3, 0); diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index b51c104a28a2..0c160675b3ac 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -1100,7 +1100,7 @@ static int applesmc_create_accelerometer(void) /* initialize the input class */ applesmc_idev->name = "applesmc"; applesmc_idev->id.bustype = BUS_HOST; - applesmc_idev->cdev.dev = &pdev->dev; + applesmc_idev->dev.parent = &pdev->dev; applesmc_idev->evbit[0] = BIT(EV_ABS); applesmc_idev->open = applesmc_idev_open; applesmc_idev->close = applesmc_idev_close; diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index f82fa2d23f95..e0cf5e6fe5bc 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -574,7 +574,7 @@ static int __init hdaps_init(void) /* initialize the input class */ hdaps_idev->name = "hdaps"; - hdaps_idev->cdev.dev = &pdev->dev; + hdaps_idev->dev.parent = &pdev->dev; hdaps_idev->evbit[0] = BIT(EV_ABS); input_set_abs_params(hdaps_idev, ABS_X, -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 434a61b415a3..96867347bcbf 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -4,6 +4,7 @@ menuconfig I2C tristate "I2C support" + depends on HAS_IOMEM ---help--- I2C (pronounce: I-square-C) is a slow serial bus protocol used in many micro controller applications and developed by Philips. SMBus, diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index f35156c58922..9c8b6d5eaec9 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/version.h> #include <linux/kernel.h> +#include <linux/err.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/delay.h> @@ -226,13 +227,14 @@ static int __devinit at91_i2c_probe(struct platform_device *pdev) adapter->algo = &at91_algorithm; adapter->class = I2C_CLASS_HWMON; adapter->dev.parent = &pdev->dev; + /* adapter->id == 0 ... only one TWI controller for now */ platform_set_drvdata(pdev, adapter); clk_enable(twi_clk); /* enable peripheral clock */ at91_twi_hwinit(); /* initialize TWI controller */ - rc = i2c_add_adapter(adapter); + rc = i2c_add_numbered_adapter(adapter); if (rc) { dev_err(&pdev->dev, "Adapter %s registration failed\n", adapter->name); @@ -295,6 +297,9 @@ static int at91_i2c_resume(struct platform_device *pdev) #define at91_i2c_resume NULL #endif +/* work with "modprobe at91_i2c" from hotplugging or coldplugging */ +MODULE_ALIAS("at91_i2c"); + static struct platform_driver at91_i2c_driver = { .probe = at91_i2c_probe, .remove = __devexit_p(at91_i2c_remove), diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 873544ab598e..8a0a99b93641 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -548,7 +548,7 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c) */ icr = readl(_ICR(i2c)); icr &= ~(ICR_STOP | ICR_ACKNAK); - writel(icr, _IRC(i2c)); + writel(icr, _ICR(i2c)); } /* diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 1d06b415ede9..9040809d2c25 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -7,6 +7,7 @@ if BLOCK menu "ATA/ATAPI/MFM/RLL support" + depends on HAS_IOMEM config IDE tristate "ATA/ATAPI/MFM/RLL support" diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig index 61d7809a5a26..8012b3b0ce75 100644 --- a/drivers/ieee1394/Kconfig +++ b/drivers/ieee1394/Kconfig @@ -1,4 +1,7 @@ menu "IEEE 1394 (FireWire) support" + depends on PCI || BROKEN + +source "drivers/firewire/Kconfig" config IEEE1394 tristate "IEEE 1394 (FireWire) support" diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 37deaae49190..994decc7bcf2 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -1,4 +1,5 @@ menu "InfiniBand support" + depends on HAS_IOMEM config INFINIBAND depends on PCI || BROKEN diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 0e9b69535ad6..f814fb3a469d 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -3,6 +3,7 @@ # menu "Input device support" + depends on !S390 config INPUT tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index c90afeea54aa..d42fe89cddf6 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -3,6 +3,7 @@ # menu "ISDN subsystem" + depends on !S390 config ISDN tristate "ISDN support" diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig index 703cc88d1ef9..e8e37d826478 100644 --- a/drivers/kvm/Kconfig +++ b/drivers/kvm/Kconfig @@ -2,6 +2,7 @@ # KVM configuration # menu "Virtualization" + depends on X86 config KVM tristate "Kernel-based Virtual Machine (KVM) support" diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 80acd08f0e97..87d2046f866c 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -1,5 +1,6 @@ menu "LED devices" + depends on HAS_IOMEM config NEW_LEDS bool "LED Support" diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 97ee870b265d..3a95cc5e029c 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -271,21 +271,25 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int */ update_head_pos(mirror, r1_bio); - if (uptodate || (conf->raid_disks - conf->mddev->degraded) <= 1) { - /* - * Set R1BIO_Uptodate in our master bio, so that - * we will return a good error code for to the higher - * levels even if IO on some other mirrored buffer fails. - * - * The 'master' represents the composite IO operation to - * user-side. So if something waits for IO, then it will - * wait for the 'master' bio. + if (uptodate) + set_bit(R1BIO_Uptodate, &r1_bio->state); + else { + /* If all other devices have failed, we want to return + * the error upwards rather than fail the last device. + * Here we redefine "uptodate" to mean "Don't want to retry" */ - if (uptodate) - set_bit(R1BIO_Uptodate, &r1_bio->state); + unsigned long flags; + spin_lock_irqsave(&conf->device_lock, flags); + if (r1_bio->mddev->degraded == conf->raid_disks || + (r1_bio->mddev->degraded == conf->raid_disks-1 && + !test_bit(Faulty, &conf->mirrors[mirror].rdev->flags))) + uptodate = 1; + spin_unlock_irqrestore(&conf->device_lock, flags); + } + if (uptodate) raid_end_bio_io(r1_bio); - } else { + else { /* * oops, read error: */ @@ -992,13 +996,14 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) unsigned long flags; spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded++; + set_bit(Faulty, &rdev->flags); spin_unlock_irqrestore(&conf->device_lock, flags); /* * if recovery is running, make sure it aborts. */ set_bit(MD_RECOVERY_ERR, &mddev->recovery); - } - set_bit(Faulty, &rdev->flags); + } else + set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n" " Operation continuing on %d devices\n", diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 91d25798ae4a..3a80e0cc7369 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -3,6 +3,7 @@ # menu "Multimedia devices" + depends on HAS_IOMEM config VIDEO_DEV tristate "Video For Linux" diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig index 71037f91c222..c88cc75ab49b 100644 --- a/drivers/message/fusion/Kconfig +++ b/drivers/message/fusion/Kconfig @@ -1,5 +1,6 @@ menu "Fusion MPT device support" + depends on PCI config FUSION bool diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig index 6443392bffff..f4ac21e5771e 100644 --- a/drivers/message/i2o/Kconfig +++ b/drivers/message/i2o/Kconfig @@ -1,5 +1,6 @@ menu "I2O device support" + depends on PCI config I2O tristate "I2O support" diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ab6e985275b2..a20a51efe118 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -3,6 +3,7 @@ # menu "Multifunction device drivers" + depends on HAS_IOMEM config MFD_SM501 tristate "Support for Silicon Motion SM501" diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 877e7909a0e5..2f2fbffafbe0 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -130,7 +130,7 @@ config SONY_LAPTOP Read <file:Documentation/sony-laptop.txt> for more information. -config SONY_LAPTOP_OLD +config SONYPI_COMPAT bool "Sonypi compatibility" depends on SONY_LAPTOP ---help--- diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 65c32a95e121..4f9060a2a2f2 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -30,7 +30,7 @@ * Eric Burghard - LED display support for W1N * Josh Green - Light Sens support * Thomas Tuttle - His first patch for led support was very helpfull - * + * Sam Lin - GPS support */ #include <linux/autoconf.h> @@ -48,7 +48,7 @@ #include <acpi/acpi_bus.h> #include <asm/uaccess.h> -#define ASUS_LAPTOP_VERSION "0.41" +#define ASUS_LAPTOP_VERSION "0.42" #define ASUS_HOTK_NAME "Asus Laptop Support" #define ASUS_HOTK_CLASS "hotkey" @@ -83,6 +83,7 @@ #define PLED_ON 0x20 //Phone LED #define GLED_ON 0x40 //Gaming LED #define LCD_ON 0x80 //LCD backlight +#define GPS_ON 0x100 //GPS #define ASUS_LOG ASUS_HOTK_FILE ": " #define ASUS_ERR KERN_ERR ASUS_LOG @@ -148,7 +149,7 @@ ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V - S5A M5A z33A W1Jc W2V */ + S5A M5A z33A W1Jc W2V G1 */ "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ @@ -162,6 +163,12 @@ ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ +/* GPS */ +/* R2H use different handle for GPS on/off */ +ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */ +ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ +ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); + /* * This is the main structure, we can use it to store anything interesting * about the hotk device @@ -278,12 +285,28 @@ static int read_wireless_status(int mask) return (hotk->status & mask) ? 1 : 0; } +static int read_gps_status(void) +{ + ulong status; + acpi_status rv = AE_OK; + + rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); + if (ACPI_FAILURE(rv)) + printk(ASUS_WARNING "Error reading GPS status\n"); + else + return status ? 1 : 0; + + return (hotk->status & GPS_ON) ? 1 : 0; +} + /* Generic LED functions */ static int read_status(int mask) { /* There is a special method for both wireless devices */ if (mask == BT_ON || mask == WL_ON) return read_wireless_status(mask); + else if (mask == GPS_ON) + return read_gps_status(); return (hotk->status & mask) ? 1 : 0; } @@ -299,6 +322,10 @@ static void write_status(acpi_handle handle, int out, int mask) case GLED_ON: out = (out & 0x1) + 1; break; + case GPS_ON: + handle = (out) ? gps_on_handle : gps_off_handle; + out = 0x02; + break; default: out &= 0x1; break; @@ -667,6 +694,21 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, return rv; } +/* + * GPS + */ +static ssize_t show_gps(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", read_status(GPS_ON)); +} + +static ssize_t store_gps(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return store_status(buf, count, NULL, GPS_ON); +} + static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) { /* TODO Find a better way to handle events count. */ @@ -715,6 +757,7 @@ static ASUS_CREATE_DEVICE_ATTR(display); static ASUS_CREATE_DEVICE_ATTR(ledd); static ASUS_CREATE_DEVICE_ATTR(ls_switch); static ASUS_CREATE_DEVICE_ATTR(ls_level); +static ASUS_CREATE_DEVICE_ATTR(gps); static struct attribute *asuspf_attributes[] = { &dev_attr_infos.attr, @@ -724,6 +767,7 @@ static struct attribute *asuspf_attributes[] = { &dev_attr_ledd.attr, &dev_attr_ls_switch.attr, &dev_attr_ls_level.attr, + &dev_attr_gps.attr, NULL }; @@ -763,6 +807,9 @@ static void asus_hotk_add_fs(void) ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); } + + if (gps_status_handle && gps_on_handle && gps_off_handle) + ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps); } static int asus_handle_init(char *name, acpi_handle * handle, @@ -890,9 +937,13 @@ static int asus_hotk_get_info(void) /* There is a lot of models with "ALSL", but a few get a real light sens, so we need to check it. */ - if (ASUS_HANDLE_INIT(ls_switch)) + if (!ASUS_HANDLE_INIT(ls_switch)) ASUS_HANDLE_INIT(ls_level); + ASUS_HANDLE_INIT(gps_on); + ASUS_HANDLE_INIT(gps_off); + ASUS_HANDLE_INIT(gps_status); + kfree(model); return AE_OK; @@ -950,7 +1001,7 @@ static int asus_hotk_add(struct acpi_device *device) * We install the handler, it will receive the hotk in parameter, so, we * could add other data to the hotk struct */ - status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + status = acpi_install_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, asus_hotk_notify, hotk); if (ACPI_FAILURE(status)) printk(ASUS_ERR "Error installing notify handler\n"); @@ -981,6 +1032,9 @@ static int asus_hotk_add(struct acpi_device *device) if (ls_level_handle) set_light_sens_level(hotk->light_level); + /* GPS is on by default */ + write_status(NULL, 1, GPS_ON); + end: if (result) { kfree(hotk->name); @@ -997,7 +1051,7 @@ static int asus_hotk_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; - status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + status = acpi_remove_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, asus_hotk_notify); if (ACPI_FAILURE(status)) printk(ASUS_ERR "Error removing notify handler\n"); diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index 68c4b58525ba..41e901f53e7c 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c @@ -85,7 +85,7 @@ static int set_lcd_level(int level) buf[0] = 0x80; buf[1] = (u8) (level*31); - return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0); + return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0, 1); } static int get_lcd_level(void) @@ -93,7 +93,7 @@ static int get_lcd_level(void) u8 wdata = 0, rdata; int result; - result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1); + result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1); if (result < 0) return result; @@ -105,7 +105,7 @@ static int get_auto_brightness(void) u8 wdata = 4, rdata; int result; - result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1); + result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1); if (result < 0) return result; @@ -119,14 +119,14 @@ static int set_auto_brightness(int enable) wdata[0] = 4; - result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1); + result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1, 1); if (result < 0) return result; wdata[0] = 0x84; wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0); - return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0); + return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1); } static int get_wireless_state(int *wlan, int *bluetooth) @@ -134,7 +134,7 @@ static int get_wireless_state(int *wlan, int *bluetooth) u8 wdata = 0, rdata; int result; - result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1); + result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1, 1); if (result < 0) return -1; diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index c15c1f61bd1b..8ee0321ef1c8 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -63,7 +63,7 @@ #include <asm/uaccess.h> #include <linux/sonypi.h> #include <linux/sony-laptop.h> -#ifdef CONFIG_SONY_LAPTOP_OLD +#ifdef CONFIG_SONYPI_COMPAT #include <linux/poll.h> #include <linux/miscdevice.h> #endif @@ -114,7 +114,7 @@ MODULE_PARM_DESC(camera, "set this to 1 to enable Motion Eye camera controls " "(only use it if you have a C1VE or C1VN model)"); -#ifdef CONFIG_SONY_LAPTOP_OLD +#ifdef CONFIG_SONYPI_COMPAT static int minor = -1; module_param(minor, int, 0); MODULE_PARM_DESC(minor, @@ -1504,7 +1504,7 @@ static struct attribute_group spic_attribute_group = { }; /******** SONYPI compatibility **********/ -#ifdef CONFIG_SONY_LAPTOP_OLD +#ifdef CONFIG_SONYPI_COMPAT /* battery / brightness / temperature addresses */ #define SONYPI_BAT_FLAGS 0x81 @@ -1798,7 +1798,7 @@ static void sonypi_compat_exit(void) static int sonypi_compat_init(void) { return 0; } static void sonypi_compat_exit(void) { } static void sonypi_compat_report_event(u8 event) { } -#endif /* CONFIG_SONY_LAPTOP_OLD */ +#endif /* CONFIG_SONYPI_COMPAT */ /* * ACPI callbacks diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 45b7d53b949c..c0b41e8bcd9d 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -4,6 +4,7 @@ menuconfig MMC tristate "MMC/SD card support" + depends on HAS_IOMEM help MMC is the "multi-media card" bus protocol. diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index c1b47db29bd2..fbec8cd55e38 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -2,6 +2,7 @@ menuconfig MTD tristate "Memory Technology Device (MTD) support" + depends on HAS_IOMEM help Memory Technology Devices are flash, RAM and similar chips, often used for solid state file systems on embedded devices. This option diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index f994f129f3d8..c0d3101eb6a0 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -3,6 +3,7 @@ # menu "PHY device support" + depends on !S390 config PHYLIB tristate "PHY Device support and infrastructure" diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index e273347dc606..e3f5bb0fe603 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -3,6 +3,7 @@ # menu "Wireless LAN" + depends on !S390 config WLAN_PRE80211 bool "Wireless LAN (pre-802.11)" diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 36c6a1bfe558..f46c69e4ed82 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -6,6 +6,7 @@ # menu "Parallel port support" + depends on HAS_IOMEM config PARPORT tristate "Parallel port support" diff --git a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig index c5143201419a..1959cef8e9de 100644 --- a/drivers/pnp/Kconfig +++ b/drivers/pnp/Kconfig @@ -3,6 +3,7 @@ # menu "Plug and Play support" + depends on HAS_IOMEM config PNP bool "Plug and Play support" diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 76422eded36e..1759baad439c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -3,6 +3,7 @@ # menu "Real Time Clock" + depends on !S390 config RTC_LIB tristate diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index b250c5354503..e879b212cf43 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig @@ -1,11 +1,9 @@ -if S390 && BLOCK - comment "S/390 block device drivers" - depends on S390 + depends on S390 && BLOCK config BLK_DEV_XPRAM tristate "XPRAM disk support" - depends on S390 + depends on S390 && BLOCK help Select this option if you want to use your expanded storage on S/390 or zSeries as a disk. This is useful as a _fast_ swap device if you @@ -15,12 +13,13 @@ config BLK_DEV_XPRAM config DCSSBLK tristate "DCSSBLK support" + depends on S390 && BLOCK help Support for dcss block device config DASD tristate "Support for DASD devices" - depends on CCW + depends on CCW && BLOCK help Enable this option if you want to access DASDs directly utilizing S/390s channel subsystem commands. This is necessary for running @@ -62,5 +61,3 @@ config DASD_EER This driver provides a character device interface to the DASD extended error reporting. This is only needed if you want to use applications written for the EER facility. - -endif diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 977521013fe8..bfeca57098fa 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2174,9 +2174,10 @@ dasd_generic_notify(struct ccw_device *cdev, int event) return ret; } -struct dasd_ccw_req * dasd_generic_build_rdc(struct dasd_device *device, - void *rdc_buffer, - int rdc_buffer_size, char *magic) +static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, + void *rdc_buffer, + int rdc_buffer_size, + char *magic) { struct dasd_ccw_req *cqr; struct ccw1 *ccw; @@ -2219,6 +2220,7 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, dasd_sfree_request(cqr, cqr->device); return ret; } +EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars); static int __init dasd_init(void) diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index e810e4a44ed4..eccac1c3b71b 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -50,6 +50,7 @@ struct dasd_diag_private { struct dasd_diag_rw_io iob; struct dasd_diag_init_io iib; blocknum_t pt_block; + struct ccw_dev_id dev_id; }; struct dasd_diag_req { @@ -102,7 +103,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize, iib = &private->iib; memset(iib, 0, sizeof (struct dasd_diag_init_io)); - iib->dev_nr = _ccw_device_get_device_number(device->cdev); + iib->dev_nr = private->dev_id.devno; iib->block_size = blocksize; iib->offset = offset; iib->flaga = DASD_DIAG_FLAGA_DEFAULT; @@ -127,7 +128,7 @@ mdsk_term_io(struct dasd_device * device) private = (struct dasd_diag_private *) device->private; iib = &private->iib; memset(iib, 0, sizeof (struct dasd_diag_init_io)); - iib->dev_nr = _ccw_device_get_device_number(device->cdev); + iib->dev_nr = private->dev_id.devno; rc = dia250(iib, TERM_BIO); return rc; } @@ -166,7 +167,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr) private = (struct dasd_diag_private *) device->private; dreq = (struct dasd_diag_req *) cqr->data; - private->iob.dev_nr = _ccw_device_get_device_number(device->cdev); + private->iob.dev_nr = private->dev_id.devno; private->iob.key = 0; private->iob.flags = DASD_DIAG_RWFLAG_ASYNC; private->iob.block_count = dreq->block_count; @@ -323,11 +324,12 @@ dasd_diag_check_device(struct dasd_device *device) "memory allocation failed for private data"); return -ENOMEM; } + ccw_device_get_id(device->cdev, &private->dev_id); device->private = (void *) private; } /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); - rdc_data->dev_nr = _ccw_device_get_device_number(device->cdev); + rdc_data->dev_nr = private->dev_id.devno; rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics); rc = diag210((struct diag210 *) rdc_data); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index c9583fbc2a7d..418b4e63a4fa 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -450,9 +450,9 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) return 0; } -struct dasd_ccw_req * dasd_eckd_build_rcd_lpm(struct dasd_device *device, - void *rcd_buffer, - struct ciw *ciw, __u8 lpm) +static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, + void *rcd_buffer, + struct ciw *ciw, __u8 lpm) { struct dasd_ccw_req *cqr; struct ccw1 *ccw; diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 758cfb542865..672eb0a3dd0b 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -255,6 +255,7 @@ dasd_ioctl_information(struct dasd_device *device, unsigned long flags; int rc; struct ccw_device *cdev; + struct ccw_dev_id dev_id; if (!device->discipline->fill_info) return -EINVAL; @@ -270,8 +271,9 @@ dasd_ioctl_information(struct dasd_device *device, } cdev = device->cdev; + ccw_device_get_id(cdev, &dev_id); - dasd_info->devno = _ccw_device_get_device_number(device->cdev); + dasd_info->devno = dev_id.devno; dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev); dasd_info->cu_type = cdev->id.cu_type; dasd_info->cu_model = cdev->id.cu_model; diff --git a/drivers/s390/Kconfig b/drivers/s390/char/Kconfig index 165af398fdea..66102a184322 100644 --- a/drivers/s390/Kconfig +++ b/drivers/s390/char/Kconfig @@ -1,69 +1,9 @@ -config CCW - bool - default y - -source "drivers/block/Kconfig" - -source "drivers/md/Kconfig" - - -menu "Character device drivers" - -config UNIX98_PTYS - bool "Unix98 PTY support" - ---help--- - A pseudo terminal (PTY) is a software device consisting of two - halves: a master and a slave. The slave device behaves identical to - a physical terminal; the master device is used by a process to - read data from and write data to the slave, thereby emulating a - terminal. Typical programs for the master side are telnet servers - and xterms. - - Linux has traditionally used the BSD-like names /dev/ptyxx for - masters and /dev/ttyxx for slaves of pseudo terminals. This scheme - has a number of problems. The GNU C library glibc 2.1 and later, - however, supports the Unix98 naming standard: in order to acquire a - pseudo terminal, a process opens /dev/ptmx; the number of the pseudo - terminal is then made available to the process and the pseudo - terminal slave can be accessed as /dev/pts/<number>. What was - traditionally /dev/ttyp2 will then be /dev/pts/2, for example. - - The entries in /dev/pts/ are created on the fly by a virtual - file system; therefore, if you say Y here you should say Y to - "/dev/pts file system for Unix98 PTYs" as well. - - If you want to say Y here, you need to have the C library glibc 2.1 - or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*"). - Read the instructions in <file:Documentation/Changes> pertaining to - pseudo terminals. It's safe to say N. - -config UNIX98_PTY_COUNT - int "Maximum number of Unix98 PTYs in use (0-2048)" - depends on UNIX98_PTYS - default "256" - help - The maximum number of Unix98 PTYs that can be used at any one time. - The default is 256, and should be enough for desktop systems. Server - machines which support incoming telnet/rlogin/ssh connections and/or - serve several X terminals may want to increase this: every incoming - connection and every xterm uses up one PTY. - - When not in use, each additional set of 256 PTYs occupy - approximately 8 KB of kernel memory on 32-bit architectures. - -config HANGCHECK_TIMER - tristate "Hangcheck timer" - help - The hangcheck-timer module detects when the system has gone - out to lunch past a certain margin. It can reboot the system - or merely print a warning. - -source "drivers/char/watchdog/Kconfig" - comment "S/390 character device drivers" + depends on S390 config TN3270 tristate "Support for locally attached 3270 terminals" + depends on CCW help Include support for IBM 3270 terminals. @@ -88,6 +28,7 @@ config TN3270_CONSOLE config TN3215 bool "Support for 3215 line mode terminal" + depends on CCW help Include support for IBM 3215 line-mode terminals. @@ -99,12 +40,19 @@ config TN3215_CONSOLE Linux system console. config CCW_CONSOLE - bool - depends on TN3215_CONSOLE || TN3270_CONSOLE - default y - + bool + depends on TN3215_CONSOLE || TN3270_CONSOLE + default y + +config SCLP + bool "Support for SCLP" + depends on S390 + help + Include support for the SCLP interface to the service element. + config SCLP_TTY bool "Support for SCLP line mode terminal" + depends on SCLP help Include support for IBM SCLP line-mode terminals. @@ -117,6 +65,7 @@ config SCLP_CONSOLE config SCLP_VT220_TTY bool "Support for SCLP VT220-compatible terminal" + depends on SCLP help Include support for an IBM SCLP VT220-compatible terminal. @@ -129,6 +78,7 @@ config SCLP_VT220_CONSOLE config SCLP_CPI tristate "Control-Program Identification" + depends on SCLP help This option enables the hardware console interface for system identification. This is commonly used for workload management and @@ -140,6 +90,7 @@ config SCLP_CPI config S390_TAPE tristate "S/390 tape device support" + depends on CCW help Select this option if you want to access channel-attached tape devices on IBM S/390 or zSeries. @@ -194,6 +145,7 @@ config VMLOGRDR config VMCP tristate "Support for the z/VM CP interface (VM only)" + depends on S390 help Select this option if you want to be able to interact with the control program on z/VM @@ -207,33 +159,8 @@ config MONREADER config MONWRITER tristate "API for writing z/VM monitor service records" + depends on S390 default "m" help Character device driver for writing z/VM monitor service records -endmenu - -menu "Cryptographic devices" - -config ZCRYPT - tristate "Support for PCI-attached cryptographic adapters" - select ZCRYPT_MONOLITHIC if ZCRYPT="y" - default "m" - help - Select this option if you want to use a PCI-attached cryptographic - adapter like: - + PCI Cryptographic Accelerator (PCICA) - + PCI Cryptographic Coprocessor (PCICC) - + PCI-X Cryptographic Coprocessor (PCIXCC) - + Crypto Express2 Coprocessor (CEX2C) - + Crypto Express2 Accelerator (CEX2A) - -config ZCRYPT_MONOLITHIC - bool "Monolithic zcrypt module" - depends on ZCRYPT="m" - help - Select this option if you want to have a single module z90crypt.ko - that contains all parts of the crypto device driver (ap bus, - request router and all the card drivers). - -endmenu diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 8df7b1323c05..67009bfa093e 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -97,7 +97,7 @@ static u8 user_data_sever[16] = { * Create the 8 bytes EBCDIC DCSS segment name from * an ASCII name, incl. padding */ -static inline void dcss_mkname(char *ascii_name, char *ebcdic_name) +static void dcss_mkname(char *ascii_name, char *ebcdic_name) { int i; @@ -191,7 +191,7 @@ static inline u32 mon_rec_end(struct mon_msg *monmsg) return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8)); } -static inline int mon_check_mca(struct mon_msg *monmsg) +static int mon_check_mca(struct mon_msg *monmsg) { if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) || (mon_rec_start(monmsg) < mon_dcss_start) || @@ -209,8 +209,8 @@ static inline int mon_check_mca(struct mon_msg *monmsg) return 0; } -static inline int mon_send_reply(struct mon_msg *monmsg, - struct mon_private *monpriv) +static int mon_send_reply(struct mon_msg *monmsg, + struct mon_private *monpriv) { int rc; @@ -236,7 +236,7 @@ static inline int mon_send_reply(struct mon_msg *monmsg, return 0; } -static inline void mon_free_mem(struct mon_private *monpriv) +static void mon_free_mem(struct mon_private *monpriv) { int i; @@ -246,7 +246,7 @@ static inline void mon_free_mem(struct mon_private *monpriv) kfree(monpriv); } -static inline struct mon_private *mon_alloc_mem(void) +static struct mon_private *mon_alloc_mem(void) { int i; struct mon_private *monpriv; @@ -307,7 +307,7 @@ static inline void mon_next_mca(struct mon_msg *monmsg) monmsg->pos = 0; } -static inline struct mon_msg *mon_next_message(struct mon_private *monpriv) +static struct mon_msg *mon_next_message(struct mon_private *monpriv) { struct mon_msg *monmsg; diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 8facd14adb7c..f6ef90ee3e7d 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -589,9 +589,10 @@ static int __raw3270_size_device_vm(struct raw3270 *rp) { int rc, model; + struct ccw_dev_id dev_id; - raw3270_init_diag210.vrdcdvno = - _ccw_device_get_device_number(rp->cdev); + ccw_device_get_id(rp->cdev, &dev_id); + raw3270_init_diag210.vrdcdvno = dev_id.devno; raw3270_init_diag210.vrdclen = sizeof(struct diag210); rc = diag210(&raw3270_init_diag210); if (rc) diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 87ac4a3ad49d..dbb99d1b6f57 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -132,6 +132,9 @@ int sclp_deactivate(void); int sclp_reactivate(void); int sclp_service_call(sclp_cmdw_t command, void *sccb); +int sclp_sdias_init(void); +void sclp_sdias_exit(void); + /* useful inlines */ /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */ diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c index 52283daddaef..1c064976b32b 100644 --- a/drivers/s390/char/sclp_sdias.c +++ b/drivers/s390/char/sclp_sdias.c @@ -66,9 +66,9 @@ static DEFINE_MUTEX(sdias_mutex); static void sdias_callback(struct sclp_req *request, void *data) { - struct sdias_sccb *sccb; + struct sdias_sccb *cbsccb; - sccb = (struct sdias_sccb *) request->sccb; + cbsccb = (struct sdias_sccb *) request->sccb; sclp_req_done = 1; wake_up(&sdias_wq); /* Inform caller, that request is complete */ TRACE("callback done\n"); @@ -229,7 +229,7 @@ out: return rc; } -int __init sdias_init(void) +int __init sclp_sdias_init(void) { int rc; @@ -248,7 +248,7 @@ int __init sdias_init(void) return 0; } -void __exit sdias_exit(void) +void __exit sclp_sdias_exit(void) { debug_unregister(sdias_dbf); sclp_unregister(&sclp_sdias_register); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 89d439316a53..66eb0688d523 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -21,6 +21,7 @@ #include <asm/debug.h> #include <asm/processor.h> #include <asm/irqflags.h> +#include "sclp.h" #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) #define MSG(x...) printk( KERN_ALERT x ) @@ -564,8 +565,6 @@ static void __init zcore_header_init(int arch, struct zcore_header *hdr) get_cpu_id(&hdr->cpu_id); } -extern int sdias_init(void); - static int __init zcore_init(void) { unsigned char arch; @@ -582,7 +581,7 @@ static int __init zcore_init(void) TRACE("wwpn: %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn); TRACE("lun: %llx\n", (unsigned long long) ipl_info.data.fcp.lun); - rc = sdias_init(); + rc = sclp_sdias_init(); if (rc) goto fail; @@ -634,12 +633,10 @@ fail: return rc; } -extern void sdias_exit(void); - static void __exit zcore_exit(void) { debug_unregister(zcore_dbf); - sdias_exit(); + sclp_sdias_exit(); diag308(DIAG308_REL_HSA, NULL); } diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 27c6d9e55b23..dfca0ef139fd 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -191,8 +191,7 @@ static int css_register_subchannel(struct subchannel *sch) return ret; } -int -css_probe_device(struct subchannel_id schid) +static int css_probe_device(struct subchannel_id schid) { int ret; struct subchannel *sch; diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 71fcfdc42800..ed7977531c3f 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -138,9 +138,7 @@ struct css_driver { * all css_drivers have the css_bus_type */ extern struct bus_type css_bus_type; -extern struct css_driver io_subchannel_driver; -extern int css_probe_device(struct subchannel_id); extern int css_sch_device_register(struct subchannel *); extern void css_sch_device_unregister(struct subchannel *); extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index a23ff582db9d..a8b373f69cf0 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -129,7 +129,7 @@ static void io_subchannel_verify(struct device *); static void io_subchannel_ioterm(struct device *); static void io_subchannel_shutdown(struct subchannel *); -struct css_driver io_subchannel_driver = { +static struct css_driver io_subchannel_driver = { .subchannel_type = SUBCHANNEL_TYPE_IO, .drv = { .name = "io_subchannel", @@ -546,7 +546,7 @@ static struct attribute_group ccwdev_attr_group = { .attrs = ccwdev_attrs, }; -struct attribute_group *ccwdev_attr_groups[] = { +static struct attribute_group *ccwdev_attr_groups[] = { &ccwdev_attr_group, NULL, }; diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 16f59fcb66b1..a5d263fb55ae 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -616,6 +616,17 @@ ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) return chp_get_chp_desc(chpid); } +/** + * ccw_device_get_id - obtain a ccw device id + * @cdev: device to obtain the id for + * @dev_id: where to fill in the values + */ +void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) +{ + *dev_id = cdev->private->dev_id; +} +EXPORT_SYMBOL(ccw_device_get_id); + // FIXME: these have to go: int diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index f770018fe1d5..e70aeb7a3781 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -1983,6 +1983,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr) if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT) qdio_mark_q(q); else { + qdio_perf_stat_dec(&perf_stats.tl_runs); __qdio_inbound_processing(q); } } diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index f98fa465df0a..eada69dec4fe 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -3,7 +3,7 @@ menu "S/390 network device drivers" config LCS tristate "Lan Channel Station Interface" - depends on NETDEVICES && (NET_ETHERNET || TR || FDDI) + depends on CCW && NETDEVICES && (NET_ETHERNET || TR || FDDI) help Select this option if you want to use LCS networking on IBM S/390 or zSeries. This device driver supports Token Ring (IEEE 802.5), @@ -13,7 +13,7 @@ config LCS config CTC tristate "CTC device support" - depends on NETDEVICES + depends on CCW && NETDEVICES help Select this option if you want to use channel-to-channel networking on IBM S/390 or zSeries. This device driver supports real CTC @@ -42,7 +42,7 @@ config SMSGIUCV config CLAW tristate "CLAW device support" - depends on NETDEVICES + depends on CCW && NETDEVICES help This driver supports channel attached CLAW devices. CLAW is Common Link Access for Workstation. Common devices @@ -52,7 +52,7 @@ config CLAW config QETH tristate "Gigabit Ethernet device support" - depends on NETDEVICES && IP_MULTICAST && QDIO + depends on CCW && NETDEVICES && IP_MULTICAST && QDIO help This driver supports the IBM S/390 and zSeries OSA Express adapters in QDIO mode (all media types), HiperSockets interfaces and VM GuestLAN diff --git a/drivers/s390/net/qeth_mpc.c b/drivers/s390/net/qeth_mpc.c index f54fdfdbf06f..f29a4bc4f6f2 100644 --- a/drivers/s390/net/qeth_mpc.c +++ b/drivers/s390/net/qeth_mpc.c @@ -162,7 +162,7 @@ struct ipa_rc_msg { char *msg; }; -struct ipa_rc_msg qeth_ipa_rc_msg[] = { +static struct ipa_rc_msg qeth_ipa_rc_msg[] = { {IPA_RC_SUCCESS, "success"}, {IPA_RC_NOTSUPP, "Command not supported"}, {IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"}, @@ -226,7 +226,7 @@ struct ipa_cmd_names { char *name; }; -struct ipa_cmd_names qeth_ipa_cmd_names[] = { +static struct ipa_cmd_names qeth_ipa_cmd_names[] = { {IPA_CMD_STARTLAN, "startlan"}, {IPA_CMD_STOPLAN, "stoplan"}, {IPA_CMD_SETVMAC, "setvmac"}, diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 324899c96efe..ddff40c4212c 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -607,8 +607,7 @@ zfcp_sg_list_free(struct zfcp_sg_list *sg_list) * @sg_count: elements in array * Return: size of entire scatter-gather list */ -size_t -zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) +static size_t zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) { unsigned int i; struct scatterlist *p; @@ -975,8 +974,7 @@ zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) mempool_destroy(adapter->pool.data_gid_pn); } -void -zfcp_dummy_release(struct device *dev) +static void zfcp_dummy_release(struct device *dev) { return; } @@ -1336,7 +1334,7 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC -void +static void zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer) { diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index d8191d115c14..5f3212440f68 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -478,7 +478,7 @@ static struct debug_view zfcp_hba_dbf_view = { NULL }; -void +static void _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id, void *buffer, int buflen) { diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e8efe938c4e7..a6f5bfbb777b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -5,6 +5,7 @@ # menu "Serial drivers" + depends on HAS_IOMEM # # The new 8250/16550 serial drivers diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index da73205e54cd..0985193dc57d 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -92,6 +92,8 @@ struct uart_sunzilog_port { #define SUNZILOG_FLAG_REGS_HELD 0x00000040 #define SUNZILOG_FLAG_TX_STOPPED 0x00000080 #define SUNZILOG_FLAG_TX_ACTIVE 0x00000100 +#define SUNZILOG_FLAG_ESCC 0x00000200 +#define SUNZILOG_FLAG_ISR_HANDLER 0x00000400 unsigned int cflag; @@ -174,9 +176,11 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel) /* This function must only be called when the TX is not busy. The UART * port lock must be held and local interrupts disabled. */ -static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs) +static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs) { int i; + int escc; + unsigned char r15; /* Let pending transmits finish. */ for (i = 0; i < 1000; i++) { @@ -229,11 +233,25 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char * write_zsreg(channel, R14, regs[R14]); /* External status interrupt control. */ - write_zsreg(channel, R15, regs[R15]); + write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN); + + /* ESCC Extension Register */ + r15 = read_zsreg(channel, R15); + if (r15 & 0x01) { + write_zsreg(channel, R7, regs[R7p]); + + /* External status interrupt and FIFO control. */ + write_zsreg(channel, R15, regs[R15] & ~WR7pEN); + escc = 1; + } else { + /* Clear FIFO bit case it is an issue */ + regs[R15] &= ~FIFOEN; + escc = 0; + } /* Reset external status interrupts. */ - write_zsreg(channel, R0, RES_EXT_INT); - write_zsreg(channel, R0, RES_EXT_INT); + write_zsreg(channel, R0, RES_EXT_INT); /* First Latch */ + write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */ /* Rewrite R3/R5, this time without enables masked. */ write_zsreg(channel, R3, regs[R3]); @@ -241,6 +259,8 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char * /* Rewrite R1, this time without IRQ enabled masked. */ write_zsreg(channel, R1, regs[R1]); + + return escc; } /* Reprogram the Zilog channel HW registers with the copies found in the @@ -731,7 +751,7 @@ static void sunzilog_enable_ms(struct uart_port *port) up->curregs[R15] = new_reg; /* NOTE: Not subject to 'transmitter active' rule. */ - write_zsreg(channel, R15, up->curregs[R15]); + write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN); } } @@ -861,44 +881,44 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, up->curregs[R14] = BRSRC | BRENAB; /* Character size, stop bits, and parity. */ - up->curregs[3] &= ~RxN_MASK; - up->curregs[5] &= ~TxN_MASK; + up->curregs[R3] &= ~RxN_MASK; + up->curregs[R5] &= ~TxN_MASK; switch (cflag & CSIZE) { case CS5: - up->curregs[3] |= Rx5; - up->curregs[5] |= Tx5; + up->curregs[R3] |= Rx5; + up->curregs[R5] |= Tx5; up->parity_mask = 0x1f; break; case CS6: - up->curregs[3] |= Rx6; - up->curregs[5] |= Tx6; + up->curregs[R3] |= Rx6; + up->curregs[R5] |= Tx6; up->parity_mask = 0x3f; break; case CS7: - up->curregs[3] |= Rx7; - up->curregs[5] |= Tx7; + up->curregs[R3] |= Rx7; + up->curregs[R5] |= Tx7; up->parity_mask = 0x7f; break; case CS8: default: - up->curregs[3] |= Rx8; - up->curregs[5] |= Tx8; + up->curregs[R3] |= Rx8; + up->curregs[R5] |= Tx8; up->parity_mask = 0xff; break; }; - up->curregs[4] &= ~0x0c; + up->curregs[R4] &= ~0x0c; if (cflag & CSTOPB) - up->curregs[4] |= SB2; + up->curregs[R4] |= SB2; else - up->curregs[4] |= SB1; + up->curregs[R4] |= SB1; if (cflag & PARENB) - up->curregs[4] |= PAR_ENAB; + up->curregs[R4] |= PAR_ENAB; else - up->curregs[4] &= ~PAR_ENAB; + up->curregs[R4] &= ~PAR_ENAB; if (!(cflag & PARODD)) - up->curregs[4] |= PAR_EVEN; + up->curregs[R4] |= PAR_EVEN; else - up->curregs[4] &= ~PAR_EVEN; + up->curregs[R4] &= ~PAR_EVEN; up->port.read_status_mask = Rx_OVR; if (iflag & INPCK) @@ -952,7 +972,9 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, static const char *sunzilog_type(struct uart_port *port) { - return "zs"; + struct uart_sunzilog_port *up = UART_ZILOG(port); + + return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs"; } /* We do not request/release mappings of the registers here, this @@ -1170,7 +1192,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) spin_lock_irqsave(&up->port.lock, flags); - up->curregs[R15] = BRKIE; + up->curregs[R15] |= BRKIE; sunzilog_convert_to_zs(up, con->cflag, 0, brg); sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); @@ -1229,7 +1251,7 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe baud = 4800; } - up->curregs[R15] = BRKIE; + up->curregs[R15] |= BRKIE; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); sunzilog_convert_to_zs(up, up->cflag, 0, brg); sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); @@ -1283,8 +1305,18 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | SUNZILOG_FLAG_CONS_MOUSE)) { + up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; + up->curregs[R6] = 0x00; /* SDLC Address */ + up->curregs[R7] = 0x7E; /* SDLC Flag */ + up->curregs[R9] = NV; + up->curregs[R7p] = 0x00; sunzilog_init_kbdms(up, up->port.line); - up->curregs[R9] |= (NV | MIE); + /* Only enable interrupts if an ISR handler available */ + if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) + up->curregs[R9] |= MIE; write_zsreg(channel, R9, up->curregs[R9]); } else { /* Normal serial TTY. */ @@ -1293,7 +1325,9 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) up->curregs[R4] = PAR_EVEN | X16CLK | SB1; up->curregs[R3] = RxENAB | Rx8; up->curregs[R5] = TxENAB | Tx8; - up->curregs[R9] = NV | MIE; + up->curregs[R6] = 0x00; /* SDLC Address */ + up->curregs[R7] = 0x7E; /* SDLC Flag */ + up->curregs[R9] = NV; up->curregs[R10] = NRZ; up->curregs[R11] = TCBR | RCBR; baud = 9600; @@ -1301,7 +1335,14 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) up->curregs[R12] = (brg & 0xff); up->curregs[R13] = (brg >> 8) & 0xff; up->curregs[R14] = BRSRC | BRENAB; - __load_zsregs(channel, up->curregs); + up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */ + up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL; + if (__load_zsregs(channel, up->curregs)) { + up->flags |= SUNZILOG_FLAG_ESCC; + } + /* Only enable interrupts if an ISR handler available */ + if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) + up->curregs[R9] |= MIE; write_zsreg(channel, R9, up->curregs[R9]); } @@ -1390,12 +1431,14 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m return err; } } else { - printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) " - "is a zs\n", - op->dev.bus_id, up[0].port.mapbase, op->irqs[0]); - printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) " - "is a zs\n", - op->dev.bus_id, up[1].port.mapbase, op->irqs[0]); + printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) " + "is a %s\n", + op->dev.bus_id, up[0].port.mapbase, op->irqs[0], + sunzilog_type (&up[0].port)); + printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) " + "is a %s\n", + op->dev.bus_id, up[1].port.mapbase, op->irqs[0], + sunzilog_type (&up[1].port)); } dev_set_drvdata(&op->dev, &up[0]); @@ -1487,10 +1530,23 @@ static int __init sunzilog_init(void) goto out_unregister_uart; if (zilog_irq != -1) { + struct uart_sunzilog_port *up = sunzilog_irq_chain; err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, "zs", sunzilog_irq_chain); if (err) goto out_unregister_driver; + + /* Enable Interrupts */ + while (up) { + struct zilog_channel __iomem *channel; + + /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */ + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + up->flags |= SUNZILOG_FLAG_ISR_HANDLER; + up->curregs[R9] |= MIE; + write_zsreg(channel, R9, up->curregs[R9]); + up = up->next; + } } out: @@ -1515,6 +1571,20 @@ static void __exit sunzilog_exit(void) of_unregister_driver(&zs_driver); if (zilog_irq != -1) { + struct uart_sunzilog_port *up = sunzilog_irq_chain; + + /* Disable Interrupts */ + while (up) { + struct zilog_channel __iomem *channel; + + /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */ + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + up->flags &= ~SUNZILOG_FLAG_ISR_HANDLER; + up->curregs[R9] &= ~MIE; + write_zsreg(channel, R9, up->curregs[R9]); + up = up->next; + } + free_irq(zilog_irq, sunzilog_irq_chain); zilog_irq = -1; } diff --git a/drivers/serial/sunzilog.h b/drivers/serial/sunzilog.h index 7939b6d71270..5dec7b47cc38 100644 --- a/drivers/serial/sunzilog.h +++ b/drivers/serial/sunzilog.h @@ -13,7 +13,8 @@ struct zilog_layout { struct zilog_channel channelA; }; -#define NUM_ZSREGS 16 +#define NUM_ZSREGS 17 +#define R7p 16 /* Written as R7 with P15 bit 0 set */ /* Conversion routines to/from brg time constants from/to bits * per second. @@ -127,6 +128,15 @@ struct zilog_layout { /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ +/* Write Register 7' (ESCC Only) */ +#define AUTO_TxFLAG 1 /* Automatic Tx SDLC Flag */ +#define AUTO_EOM_RST 2 /* Automatic EOM Reset */ +#define AUTOnRTS 4 /* Automatic /RTS pin deactivation */ +#define RxFIFO_LVL 8 /* Receive FIFO interrupt level */ +#define nDTRnREQ 0x10 /* /DTR/REQ timing */ +#define TxFIFO_LVL 0x20 /* Transmit FIFO interrupt level */ +#define EXT_RD_EN 0x40 /* Extended read register enable */ + /* Write Register 8 (transmit buffer) */ /* Write Register 9 (Master interrupt control) */ @@ -135,6 +145,7 @@ struct zilog_layout { #define DLC 4 /* Disable Lower Chain */ #define MIE 8 /* Master Interrupt Enable */ #define STATHI 0x10 /* Status high */ +#define SWIACK 0x20 /* Software Interrupt Ack (not on NMOS) */ #define NORESET 0 /* No reset on write to R9 */ #define CHRB 0x40 /* Reset channel B */ #define CHRA 0x80 /* Reset channel A */ @@ -187,7 +198,9 @@ struct zilog_layout { #define SNRZI 0xe0 /* Set NRZI mode */ /* Write Register 15 (external/status interrupt control) */ +#define WR7pEN 1 /* WR7' Enable (ESCC only) */ #define ZCIE 2 /* Zero count IE */ +#define FIFOEN 4 /* FIFO Enable (ESCC only) */ #define DCDIE 8 /* DCD IE */ #define SYNCIE 0x10 /* Sync/hunt IE */ #define CTSIE 0x20 /* CTS IE */ @@ -241,6 +254,10 @@ struct zilog_layout { #define CHATxIP 0x10 /* Channel A Tx IP */ #define CHARxIP 0x20 /* Channel A Rx IP */ +/* Read Register 6 (LSB frame byte count [Not on NMOS]) */ + +/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */ + /* Read Register 8 (receive data register) */ /* Read Register 10 (misc status bits) */ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 07c587ec71be..7c9d37f651e3 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -6,6 +6,7 @@ # fully appropriate there, so it'd need some thought to do well. # menu "SPI support" + depends on HAS_IOMEM config SPI bool "SPI support" diff --git a/drivers/telephony/Kconfig b/drivers/telephony/Kconfig index 7625b1816baf..dd1d6a53f3c0 100644 --- a/drivers/telephony/Kconfig +++ b/drivers/telephony/Kconfig @@ -3,6 +3,7 @@ # menu "Telephony Support" + depends on HAS_IOMEM config PHONE tristate "Linux telephony support" diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 278a22cea5bf..15499b7e33f4 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -3,6 +3,7 @@ # menu "USB support" + depends on HAS_IOMEM # Host-side USB depends on having a host controller # NOTE: dummy_hcd is always an option, but it's ignored here ... diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 9a256d2ff9dc..f54438828cb9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -3,6 +3,7 @@ # menu "Graphics support" + depends on HAS_IOMEM source "drivers/video/backlight/Kconfig" source "drivers/video/display/Kconfig" diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index c287a9ae4fdd..ca75b3ad3a2e 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -1,4 +1,5 @@ menu "Dallas's 1-wire bus" + depends on HAS_IOMEM config W1 tristate "Dallas's 1-wire support" diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h index 2198006d2d03..d963ef4daee8 100644 --- a/fs/afs/afs_fs.h +++ b/fs/afs/afs_fs.h @@ -31,6 +31,8 @@ enum AFS_FS_Operations { FSGETVOLUMEINFO = 148, /* AFS Get root volume information */ FSGETROOTVOLUME = 151, /* AFS Get root volume name */ FSLOOKUP = 161, /* AFS lookup file in directory */ + FSFETCHDATA64 = 65537, /* AFS Fetch file data */ + FSSTOREDATA64 = 65538, /* AFS Store file data */ }; enum AFS_FS_Errors { diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 025b1903d9e1..56cc0efa2a0c 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -293,9 +293,33 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, case 0: call->offset = 0; call->unmarshall++; + if (call->operation_ID != FSFETCHDATA64) { + call->unmarshall++; + goto no_msw; + } - /* extract the returned data length */ + /* extract the upper part of the returned data length of an + * FSFETCHDATA64 op (which should always be 0 using this + * client) */ case 1: + _debug("extract data length (MSW)"); + ret = afs_extract_data(call, skb, last, &call->tmp, 4); + switch (ret) { + case 0: break; + case -EAGAIN: return 0; + default: return ret; + } + + call->count = ntohl(call->tmp); + _debug("DATA length MSW: %u", call->count); + if (call->count > 0) + return -EBADMSG; + call->offset = 0; + call->unmarshall++; + + no_msw: + /* extract the returned data length */ + case 2: _debug("extract data length"); ret = afs_extract_data(call, skb, last, &call->tmp, 4); switch (ret) { @@ -312,7 +336,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, call->unmarshall++; /* extract the returned data */ - case 2: + case 3: _debug("extract data"); if (call->count > 0) { page = call->reply3; @@ -331,7 +355,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, call->unmarshall++; /* extract the metadata */ - case 3: + case 4: ret = afs_extract_data(call, skb, last, call->buffer, (21 + 3 + 6) * 4); switch (ret) { @@ -349,7 +373,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, call->offset = 0; call->unmarshall++; - case 4: + case 5: _debug("trailer"); if (skb->len != 0) return -EBADMSG; @@ -381,6 +405,56 @@ static const struct afs_call_type afs_RXFSFetchData = { .destructor = afs_flat_call_destructor, }; +static const struct afs_call_type afs_RXFSFetchData64 = { + .name = "FS.FetchData64", + .deliver = afs_deliver_fs_fetch_data, + .abort_to_error = afs_abort_to_error, + .destructor = afs_flat_call_destructor, +}; + +/* + * fetch data from a very large file + */ +static int afs_fs_fetch_data64(struct afs_server *server, + struct key *key, + struct afs_vnode *vnode, + off_t offset, size_t length, + struct page *buffer, + const struct afs_wait_mode *wait_mode) +{ + struct afs_call *call; + __be32 *bp; + + _enter(""); + + ASSERTCMP(length, <, ULONG_MAX); + + call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); + if (!call) + return -ENOMEM; + + call->key = key; + call->reply = vnode; + call->reply2 = NULL; /* volsync */ + call->reply3 = buffer; + call->service_id = FS_SERVICE; + call->port = htons(AFS_FS_PORT); + call->operation_ID = FSFETCHDATA64; + + /* marshall the parameters */ + bp = call->request; + bp[0] = htonl(FSFETCHDATA64); + bp[1] = htonl(vnode->fid.vid); + bp[2] = htonl(vnode->fid.vnode); + bp[3] = htonl(vnode->fid.unique); + bp[4] = htonl(upper_32_bits(offset)); + bp[5] = htonl((u32) offset); + bp[6] = 0; + bp[7] = htonl((u32) length); + + return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); +} + /* * fetch data from a file */ @@ -394,6 +468,10 @@ int afs_fs_fetch_data(struct afs_server *server, struct afs_call *call; __be32 *bp; + if (upper_32_bits(offset) || upper_32_bits(offset + length)) + return afs_fs_fetch_data64(server, key, vnode, offset, length, + buffer, wait_mode); + _enter(""); call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); @@ -406,6 +484,7 @@ int afs_fs_fetch_data(struct afs_server *server, call->reply3 = buffer; call->service_id = FS_SERVICE; call->port = htons(AFS_FS_PORT); + call->operation_ID = FSFETCHDATA; /* marshall the parameters */ bp = call->request; @@ -1032,6 +1111,73 @@ static const struct afs_call_type afs_RXFSStoreData = { .destructor = afs_flat_call_destructor, }; +static const struct afs_call_type afs_RXFSStoreData64 = { + .name = "FS.StoreData64", + .deliver = afs_deliver_fs_store_data, + .abort_to_error = afs_abort_to_error, + .destructor = afs_flat_call_destructor, +}; + +/* + * store a set of pages to a very large file + */ +static int afs_fs_store_data64(struct afs_server *server, + struct afs_writeback *wb, + pgoff_t first, pgoff_t last, + unsigned offset, unsigned to, + loff_t size, loff_t pos, loff_t i_size, + const struct afs_wait_mode *wait_mode) +{ + struct afs_vnode *vnode = wb->vnode; + struct afs_call *call; + __be32 *bp; + + _enter(",%x,{%x:%u},,", + key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); + + call = afs_alloc_flat_call(&afs_RXFSStoreData64, + (4 + 6 + 3 * 2) * 4, + (21 + 6) * 4); + if (!call) + return -ENOMEM; + + call->wb = wb; + call->key = wb->key; + call->reply = vnode; + call->service_id = FS_SERVICE; + call->port = htons(AFS_FS_PORT); + call->mapping = vnode->vfs_inode.i_mapping; + call->first = first; + call->last = last; + call->first_offset = offset; + call->last_to = to; + call->send_pages = true; + call->store_version = vnode->status.data_version + 1; + + /* marshall the parameters */ + bp = call->request; + *bp++ = htonl(FSSTOREDATA64); + *bp++ = htonl(vnode->fid.vid); + *bp++ = htonl(vnode->fid.vnode); + *bp++ = htonl(vnode->fid.unique); + + *bp++ = 0; /* mask */ + *bp++ = 0; /* mtime */ + *bp++ = 0; /* owner */ + *bp++ = 0; /* group */ + *bp++ = 0; /* unix mode */ + *bp++ = 0; /* segment size */ + + *bp++ = htonl(pos >> 32); + *bp++ = htonl((u32) pos); + *bp++ = htonl(size >> 32); + *bp++ = htonl((u32) size); + *bp++ = htonl(i_size >> 32); + *bp++ = htonl((u32) i_size); + + return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); +} + /* * store a set of pages */ @@ -1062,7 +1208,9 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb, (unsigned long long) size, (unsigned long long) pos, (unsigned long long) i_size); - BUG_ON(i_size > 0xffffffff); // TODO: use 64-bit store + if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) + return afs_fs_store_data64(server, wb, first, last, offset, to, + size, pos, i_size, wait_mode); call = afs_alloc_flat_call(&afs_RXFSStoreData, (4 + 6 + 3) * 4, @@ -1158,6 +1306,61 @@ static const struct afs_call_type afs_RXFSStoreData_as_Status = { .destructor = afs_flat_call_destructor, }; +static const struct afs_call_type afs_RXFSStoreData64_as_Status = { + .name = "FS.StoreData64", + .deliver = afs_deliver_fs_store_status, + .abort_to_error = afs_abort_to_error, + .destructor = afs_flat_call_destructor, +}; + +/* + * set the attributes on a very large file, using FS.StoreData rather than + * FS.StoreStatus so as to alter the file size also + */ +static int afs_fs_setattr_size64(struct afs_server *server, struct key *key, + struct afs_vnode *vnode, struct iattr *attr, + const struct afs_wait_mode *wait_mode) +{ + struct afs_call *call; + __be32 *bp; + + _enter(",%x,{%x:%u},,", + key_serial(key), vnode->fid.vid, vnode->fid.vnode); + + ASSERT(attr->ia_valid & ATTR_SIZE); + + call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status, + (4 + 6 + 3 * 2) * 4, + (21 + 6) * 4); + if (!call) + return -ENOMEM; + + call->key = key; + call->reply = vnode; + call->service_id = FS_SERVICE; + call->port = htons(AFS_FS_PORT); + call->store_version = vnode->status.data_version + 1; + call->operation_ID = FSSTOREDATA; + + /* marshall the parameters */ + bp = call->request; + *bp++ = htonl(FSSTOREDATA64); + *bp++ = htonl(vnode->fid.vid); + *bp++ = htonl(vnode->fid.vnode); + *bp++ = htonl(vnode->fid.unique); + + xdr_encode_AFS_StoreStatus(&bp, attr); + + *bp++ = 0; /* position of start of write */ + *bp++ = 0; + *bp++ = 0; /* size of write */ + *bp++ = 0; + *bp++ = htonl(attr->ia_size >> 32); /* new file length */ + *bp++ = htonl((u32) attr->ia_size); + + return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); +} + /* * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus * so as to alter the file size also @@ -1173,7 +1376,9 @@ static int afs_fs_setattr_size(struct afs_server *server, struct key *key, key_serial(key), vnode->fid.vid, vnode->fid.vnode); ASSERT(attr->ia_valid & ATTR_SIZE); - ASSERTCMP(attr->ia_size, <=, 0xffffffff); // TODO: use 64-bit store + if (attr->ia_size >> 32) + return afs_fs_setattr_size64(server, key, vnode, attr, + wait_mode); call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status, (4 + 6 + 3) * 4, diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 04189c47d6a0..1b36f45076ad 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -294,7 +294,7 @@ int afs_send_pages(struct afs_call *call, struct msghdr *msg, struct kvec *iov) put_page(pages[loop]); if (ret < 0) break; - } while (first < last); + } while (first <= last); _leave(" = %d", ret); return ret; diff --git a/fs/afs/write.c b/fs/afs/write.c index 83ff29262816..67ae4dbf66b3 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -122,7 +122,7 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page, if (offset == 0 && to == PAGE_SIZE) return 0; - p = kmap(page); + p = kmap_atomic(page, KM_USER0); i_size = i_size_read(&vnode->vfs_inode); pos = (loff_t) page->index << PAGE_SHIFT; @@ -133,7 +133,7 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page, memset(p, 0, offset); if (to < PAGE_SIZE) memset(p + to, 0, PAGE_SIZE - to); - kunmap(page); + kunmap_atomic(p, KM_USER0); return 0; } @@ -152,7 +152,7 @@ static int afs_prepare_page(struct afs_vnode *vnode, struct page *page, memset(p + eof, 0, PAGE_SIZE - eof); } - kunmap(p); + kunmap_atomic(p, KM_USER0); ret = 0; if (offset > 0 || eof > to) { @@ -489,14 +489,6 @@ int afs_writepage(struct page *page, struct writeback_control *wbc) _enter("{%lx},", page->index); - if (wbc->sync_mode != WB_SYNC_NONE) - wait_on_page_writeback(page); - - if (PageWriteback(page) || !PageDirty(page)) { - unlock_page(page); - return 0; - } - wb = (struct afs_writeback *) page_private(page); ASSERT(wb != NULL); @@ -677,7 +669,7 @@ void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call) pagevec_init(&pv, 0); do { - _debug("attach %lx-%lx", first, last); + _debug("done %lx-%lx", first, last); count = last - first + 1; if (count > PAGEVEC_SIZE) @@ -709,7 +701,7 @@ void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call) } __pagevec_release(&pv); - } while (first < last); + } while (first <= last); _leave(""); } diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index 2e975c0a35e1..a93620ce4aca 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c @@ -144,7 +144,8 @@ static struct kobj_type mlog_ktype = { }; static struct kset mlog_kset = { - .kobj = {.name = "logmask", .ktype = &mlog_ktype}, + .kobj = {.name = "logmask"}, + .ktype = &mlog_ktype }; int mlog_sys_init(struct kset *o2cb_subsys) @@ -157,7 +158,7 @@ int mlog_sys_init(struct kset *o2cb_subsys) } mlog_attr_ptrs[i] = NULL; - kobj_set_kset_s(&mlog_kset, o2cb_subsys); + kobj_set_kset_s(&mlog_kset, *o2cb_subsys); return kset_register(&mlog_kset); } diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h index cb8d2868c8ac..7f690bb0f02f 100644 --- a/include/acpi/acdispat.h +++ b/include/acpi/acdispat.h @@ -290,12 +290,9 @@ acpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state); acpi_status acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state); -struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, - union acpi_parse_object - *origin, - union acpi_operand_object - *mth_desc, - struct acpi_thread_state +struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object + *origin, union acpi_operand_object + *mth_desc, struct acpi_thread_state *thread); acpi_status diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index 24c3f05ab367..347a911d8237 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -319,7 +319,7 @@ ACPI_EXTERN struct acpi_fixed_event_handler acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS]; ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head; ACPI_EXTERN struct acpi_gpe_block_info - *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]; +*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]; /***************************************************************************** * diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h index 440983019993..ce7c9d653910 100644 --- a/include/acpi/acinterp.h +++ b/include/acpi/acinterp.h @@ -253,8 +253,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread); -void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc, - struct acpi_thread_state *thread); +void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc); /* * exprep - ACPI AML execution - prep utilities @@ -446,10 +445,14 @@ acpi_ex_copy_integer_to_buffer_field(union acpi_operand_object *source_desc, /* * exutils - interpreter/scanner utilities */ -acpi_status acpi_ex_enter_interpreter(void); +void acpi_ex_enter_interpreter(void); void acpi_ex_exit_interpreter(void); +void acpi_ex_reacquire_interpreter(void); + +void acpi_ex_relinquish_interpreter(void); + void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc); u8 acpi_ex_acquire_global_lock(u32 rule); diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 6f83ddbed3af..202cd4242ba1 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -630,7 +630,7 @@ ACPI_PARSE_COMMON}; * and bytelists. */ struct acpi_parse_obj_named { - ACPI_PARSE_COMMON u8 * path; + ACPI_PARSE_COMMON u8 *path; u8 *data; /* AML body or bytelist data */ u32 length; /* AML length */ u32 name; /* 4-byte name or zero if no name */ diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h index 535b7e1c41bc..5ef38a6c8a61 100644 --- a/include/acpi/acnamesp.h +++ b/include/acpi/acnamesp.h @@ -100,10 +100,8 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_walk_callback user_function, void *context, void **return_value); -struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, - struct acpi_namespace_node - *parent, - struct acpi_namespace_node +struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node + *parent, struct acpi_namespace_node *child); /* diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h index 5206d61d74a6..7e1211a8b8fa 100644 --- a/include/acpi/acobject.h +++ b/include/acpi/acobject.h @@ -155,7 +155,7 @@ struct acpi_object_event { struct acpi_object_mutex { ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */ u16 acquisition_depth; /* Allow multiple Acquires, same thread */ - acpi_thread_id owner_thread_id; /* Current owner of the mutex */ + struct acpi_thread_state *owner_thread; /* Current owner of the mutex */ acpi_mutex os_mutex; /* Actual OS synchronization object */ union acpi_operand_object *prev; /* Link for list of acquired mutexes */ union acpi_operand_object *next; /* Link for list of acquired mutexes */ @@ -216,7 +216,7 @@ struct acpi_object_processor { /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */ u8 proc_id; u8 length; - ACPI_COMMON_NOTIFY_INFO acpi_io_address address; + ACPI_COMMON_NOTIFY_INFO acpi_io_address address; }; struct acpi_object_thermal_zone { diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 9cfd5b1a48eb..c6fa5e023bc7 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -91,7 +91,8 @@ typedef int (*acpi_op_remove) (struct acpi_device * device, int type); typedef int (*acpi_op_lock) (struct acpi_device * device, int type); typedef int (*acpi_op_start) (struct acpi_device * device); typedef int (*acpi_op_stop) (struct acpi_device * device, int type); -typedef int (*acpi_op_suspend) (struct acpi_device * device, pm_message_t state); +typedef int (*acpi_op_suspend) (struct acpi_device * device, + pm_message_t state); typedef int (*acpi_op_resume) (struct acpi_device * device); typedef int (*acpi_op_scan) (struct acpi_device * device); typedef int (*acpi_op_bind) (struct acpi_device * device); @@ -296,7 +297,7 @@ struct acpi_device { void *driver_data; struct device dev; struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */ - enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ + enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ }; #define acpi_driver_data(d) ((d)->driver_data) @@ -338,7 +339,7 @@ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type); int acpi_bus_trim(struct acpi_device *start, int rmdevice); int acpi_bus_start(struct acpi_device *device); -acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd); +acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); int acpi_match_ids(struct acpi_device *device, char *ids); int acpi_create_dir(struct acpi_device *); void acpi_remove_dir(struct acpi_device *); @@ -363,6 +364,6 @@ acpi_handle acpi_get_child(acpi_handle, acpi_integer); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) -#endif /* CONFIG_ACPI */ +#endif /* CONFIG_ACPI */ #endif /*__ACPI_BUS_H__*/ diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index f6275b0e66dd..553515912c0b 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -113,7 +113,8 @@ extern int is_dock_device(acpi_handle handle); extern int register_dock_notifier(struct notifier_block *nb); extern void unregister_dock_notifier(struct notifier_block *nb); extern int register_hotplug_dock_device(acpi_handle handle, - acpi_notify_handler handler, void *context); + acpi_notify_handler handler, + void *context); extern void unregister_hotplug_dock_device(acpi_handle handle); #else static inline int is_dock_device(acpi_handle handle) @@ -128,7 +129,8 @@ static inline void unregister_dock_notifier(struct notifier_block *nb) { } static inline int register_hotplug_dock_device(acpi_handle handle, - acpi_notify_handler handler, void *context) + acpi_notify_handler handler, + void *context) { return -ENODEV; } diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h index 1049f2a0a6db..f9d2bde9a7bb 100644 --- a/include/acpi/acpi_numa.h +++ b/include/acpi/acpi_numa.h @@ -8,7 +8,7 @@ #if MAX_NUMNODES > 256 #define MAX_PXM_DOMAINS MAX_NUMNODES #else -#define MAX_PXM_DOMAINS (256) /* Old pxm spec is defined 8 bit */ +#define MAX_PXM_DOMAINS (256) /* Old pxm spec is defined 8 bit */ #endif extern int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]; diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 2785058c82ab..5e07db0d46e9 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -143,7 +143,8 @@ void acpi_os_release_mutex(acpi_mutex handle); */ void *acpi_os_allocate(acpi_size size); -void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_native_uint length); +void __iomem *acpi_os_map_memory(acpi_physical_address where, + acpi_native_uint length); void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 56bf492e7acc..fe8abc276437 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -344,7 +344,7 @@ typedef u32 acpi_integer; /* 64-bit integers */ -typedef unsigned long long acpi_integer; +typedef unsigned long long acpi_integer; #define ACPI_INTEGER_MAX ACPI_UINT64_MAX #define ACPI_INTEGER_BIT_SIZE 64 #define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */ diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h index 883ffe92148f..15a838862cd4 100644 --- a/include/acpi/acutils.h +++ b/include/acpi/acutils.h @@ -498,7 +498,8 @@ acpi_ut_display_init_pathname(u8 type, acpi_status acpi_ut_walk_aml_resources(u8 * aml, acpi_size aml_length, - acpi_walk_aml_callback user_function, void **context); + acpi_walk_aml_callback user_function, + void **context); acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index); diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 5f532d2ac180..a568717f98c6 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -103,7 +103,10 @@ #define acpi_thread_id struct task_struct * -static inline acpi_thread_id acpi_os_get_thread_id(void) { return current; } +static inline acpi_thread_id acpi_os_get_thread_id(void) +{ + return current; +} /* * The irqs_disabled() check is for resume from RAM. @@ -112,15 +115,19 @@ static inline acpi_thread_id acpi_os_get_thread_id(void) { return current; } * to quiet __might_sleep() in kmalloc() and resume does not. */ #include <acpi/actypes.h> -static inline void *acpi_os_allocate(acpi_size size) { - return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); +static inline void *acpi_os_allocate(acpi_size size) +{ + return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); } -static inline void *acpi_os_allocate_zeroed(acpi_size size) { - return kzalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); +static inline void *acpi_os_allocate_zeroed(acpi_size size) +{ + return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); } -static inline void *acpi_os_acquire_object(acpi_cache_t * cache) { - return kmem_cache_zalloc(cache, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); +static inline void *acpi_os_acquire_object(acpi_cache_t * cache) +{ + return kmem_cache_zalloc(cache, + irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); } #define ACPI_ALLOCATE(a) acpi_os_allocate(a) diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 916c0102db5b..b4b0ffdab098 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -18,7 +18,7 @@ #define ACPI_PDC_REVISION_ID 0x1 -#define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */ +#define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */ #define ACPI_PSD_REV0_ENTRIES 5 /* @@ -189,8 +189,9 @@ struct acpi_processor_errata { } piix4; }; -extern int acpi_processor_preregister_performance( - struct acpi_processor_performance **performance); +extern int acpi_processor_preregister_performance(struct + acpi_processor_performance + **performance); extern int acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu); @@ -213,7 +214,8 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr); void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, unsigned int cpu); int acpi_processor_ffh_cstate_probe(unsigned int cpu, - struct acpi_processor_cx *cx, struct acpi_power_register *reg); + struct acpi_processor_cx *cx, + struct acpi_power_register *reg); void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cstate); #else static inline void acpi_processor_power_init_bm_check(struct @@ -224,12 +226,14 @@ static inline void acpi_processor_power_init_bm_check(struct return; } static inline int acpi_processor_ffh_cstate_probe(unsigned int cpu, - struct acpi_processor_cx *cx, struct acpi_power_register *reg) + struct acpi_processor_cx *cx, + struct acpi_power_register + *reg) { return -1; } -static inline void acpi_processor_ffh_cstate_enter( - struct acpi_processor_cx *cstate) +static inline void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx + *cstate) { return; } diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h index bc5c12c13581..d7a0512f88e0 100644 --- a/include/asm-i386/paravirt.h +++ b/include/asm-i386/paravirt.h @@ -222,11 +222,6 @@ struct paravirt_ops void (*iret)(void); }; -/* Mark a paravirt probe function. */ -#define paravirt_probe(fn) \ - static asmlinkage void (*__paravirtprobe_##fn)(void) __attribute_used__ \ - __attribute__((__section__(".paravirtprobe"))) = fn - extern struct paravirt_ops paravirt_ops; #define PARAVIRT_PATCH(x) \ diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h index 6795ecefd15b..4c2e1710f157 100644 --- a/include/asm-s390/ccwdev.h +++ b/include/asm-s390/ccwdev.h @@ -16,6 +16,7 @@ /* structs from asm/cio.h */ struct irb; struct ccw1; +struct ccw_dev_id; /* simplified initializers for struct ccw_device: * CCW_DEVICE and CCW_DEVICE_DEVTYPE initialize one @@ -175,6 +176,7 @@ extern int ccw_device_set_offline(struct ccw_device *cdev); extern struct ciw *ccw_device_get_ciw(struct ccw_device *, __u32 cmd); extern __u8 ccw_device_get_path_mask(struct ccw_device *); +extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *); #define get_ccwdev_lock(x) (x)->ccwlock @@ -184,7 +186,6 @@ extern __u8 ccw_device_get_path_mask(struct ccw_device *); extern struct ccw_device *ccw_device_probe_console(void); // FIXME: these have to go -extern int _ccw_device_get_device_number(struct ccw_device *); extern int _ccw_device_get_subchannel_number(struct ccw_device *); extern void *ccw_device_get_chp_desc(struct ccw_device *, int); diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h index bdcd448d43fb..2c40fd3a137f 100644 --- a/include/asm-s390/ipl.h +++ b/include/asm-s390/ipl.h @@ -79,8 +79,8 @@ struct ipl_parameter_block { * IPL validity flags */ extern u32 ipl_flags; - extern u32 dump_prefix_page; +extern unsigned int zfcpdump_prefix_array[]; extern void do_reipl(void); extern void ipl_save_parameters(void); diff --git a/include/asm-s390/param.h b/include/asm-s390/param.h index 085a7e229b23..34aaa4603347 100644 --- a/include/asm-s390/param.h +++ b/include/asm-s390/param.h @@ -10,7 +10,7 @@ #define _ASMS390_PARAM_H #ifdef __KERNEL__ -# define HZ 100 /* Internal kernel timer frequency */ +# define HZ CONFIG_HZ /* Internal kernel timer frequency */ # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ #endif diff --git a/include/asm-sparc64/openprom.h b/include/asm-sparc64/openprom.h index e01b80559c93..26ec046715c8 100644 --- a/include/asm-sparc64/openprom.h +++ b/include/asm-sparc64/openprom.h @@ -177,7 +177,7 @@ struct linux_nodeops { /* More fun PROM structures for device probing. */ #define PROMREG_MAX 24 #define PROMVADDR_MAX 16 -#define PROMINTR_MAX 15 +#define PROMINTR_MAX 32 struct linux_prom_registers { unsigned which_io; /* hi part of physical address */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 8bcfaa4c66ae..fccd8b548d93 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -182,7 +182,8 @@ extern int ec_read(u8 addr, u8 *val); extern int ec_write(u8 addr, u8 val); extern int ec_transaction(u8 command, const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len); + u8 *rdata, unsigned rdata_len, + int force_poll); #endif /*CONFIG_ACPI_EC*/ diff --git a/include/linux/crc-itu-t.h b/include/linux/crc-itu-t.h new file mode 100644 index 000000000000..84920f3cc83e --- /dev/null +++ b/include/linux/crc-itu-t.h @@ -0,0 +1,28 @@ +/* + * crc-itu-t.h - CRC ITU-T V.41 routine + * + * Implements the standard CRC ITU-T V.41: + * Width 16 + * Poly 0x0x1021 (x^16 + x^12 + x^15 + 1) + * Init 0 + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#ifndef CRC_ITU_T_H +#define CRC_ITU_T_H + +#include <linux/types.h> + +extern u16 const crc_itu_t_table[256]; + +extern u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len); + +static inline u16 crc_itu_t_byte(u16 crc, const u8 data) +{ + return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ data) & 0xff]; +} + +#endif /* CRC_ITU_T_H */ + diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h new file mode 100644 index 000000000000..d4455eb2ae35 --- /dev/null +++ b/include/linux/firewire-cdev.h @@ -0,0 +1,229 @@ +/* + * Char device interface. + * + * Copyright (C) 2005-2006 Kristian Hoegsberg <krh@bitplanet.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _LINUX_FIREWIRE_CDEV_H +#define _LINUX_FIREWIRE_CDEV_H + +#include <linux/ioctl.h> +#include <linux/types.h> +#include <linux/firewire-constants.h> + +#define FW_CDEV_EVENT_BUS_RESET 0x00 +#define FW_CDEV_EVENT_RESPONSE 0x01 +#define FW_CDEV_EVENT_REQUEST 0x02 +#define FW_CDEV_EVENT_ISO_INTERRUPT 0x03 + +/* The 'closure' fields are for user space to use. Data passed in the + * 'closure' field for a request will be returned in the corresponding + * event. It's a 64-bit type so that it's a fixed size type big + * enough to hold a pointer on all platforms. */ + +struct fw_cdev_event_common { + __u64 closure; + __u32 type; +}; + +struct fw_cdev_event_bus_reset { + __u64 closure; + __u32 type; + __u32 node_id; + __u32 local_node_id; + __u32 bm_node_id; + __u32 irm_node_id; + __u32 root_node_id; + __u32 generation; +}; + +struct fw_cdev_event_response { + __u64 closure; + __u32 type; + __u32 rcode; + __u32 length; + __u32 data[0]; +}; + +struct fw_cdev_event_request { + __u64 closure; + __u32 type; + __u32 tcode; + __u64 offset; + __u32 handle; + __u32 length; + __u32 data[0]; +}; + +struct fw_cdev_event_iso_interrupt { + __u64 closure; + __u32 type; + __u32 cycle; + __u32 header_length; /* Length in bytes of following headers. */ + __u32 header[0]; +}; + +union fw_cdev_event { + struct fw_cdev_event_common common; + struct fw_cdev_event_bus_reset bus_reset; + struct fw_cdev_event_response response; + struct fw_cdev_event_request request; + struct fw_cdev_event_iso_interrupt iso_interrupt; +}; + +#define FW_CDEV_IOC_GET_INFO _IOWR('#', 0x00, struct fw_cdev_get_info) +#define FW_CDEV_IOC_SEND_REQUEST _IOW('#', 0x01, struct fw_cdev_send_request) +#define FW_CDEV_IOC_ALLOCATE _IOWR('#', 0x02, struct fw_cdev_allocate) +#define FW_CDEV_IOC_DEALLOCATE _IOW('#', 0x03, struct fw_cdev_deallocate) +#define FW_CDEV_IOC_SEND_RESPONSE _IOW('#', 0x04, struct fw_cdev_send_response) +#define FW_CDEV_IOC_INITIATE_BUS_RESET _IOW('#', 0x05, struct fw_cdev_initiate_bus_reset) +#define FW_CDEV_IOC_ADD_DESCRIPTOR _IOWR('#', 0x06, struct fw_cdev_add_descriptor) +#define FW_CDEV_IOC_REMOVE_DESCRIPTOR _IOW('#', 0x07, struct fw_cdev_remove_descriptor) + +#define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IOWR('#', 0x08, struct fw_cdev_create_iso_context) +#define FW_CDEV_IOC_QUEUE_ISO _IOWR('#', 0x09, struct fw_cdev_queue_iso) +#define FW_CDEV_IOC_START_ISO _IOW('#', 0x0a, struct fw_cdev_start_iso) +#define FW_CDEV_IOC_STOP_ISO _IOW('#', 0x0b, struct fw_cdev_stop_iso) + +/* FW_CDEV_VERSION History + * + * 1 Feb 18, 2007: Initial version. + */ +#define FW_CDEV_VERSION 1 + +struct fw_cdev_get_info { + /* The version field is just a running serial number. We + * never break backwards compatibility. Userspace passes in + * the version it expects and the kernel passes back the + * highest version it can provide. Even if the structs in + * this interface are extended in a later version, the kernel + * will not copy back more data than what was present in the + * interface version userspace expects. */ + __u32 version; + + /* If non-zero, at most rom_length bytes of config rom will be + * copied into that user space address. In either case, + * rom_length is updated with the actual length of the config + * rom. */ + __u32 rom_length; + __u64 rom; + + /* If non-zero, a fw_cdev_event_bus_reset struct will be + * copied here with the current state of the bus. This does + * not cause a bus reset to happen. The value of closure in + * this and sub-sequent bus reset events is set to + * bus_reset_closure. */ + __u64 bus_reset; + __u64 bus_reset_closure; + + /* The index of the card this devices belongs to. */ + __u32 card; +}; + +struct fw_cdev_send_request { + __u32 tcode; + __u32 length; + __u64 offset; + __u64 closure; + __u64 data; + __u32 generation; +}; + +struct fw_cdev_send_response { + __u32 rcode; + __u32 length; + __u64 data; + __u32 handle; +}; + +struct fw_cdev_allocate { + __u64 offset; + __u64 closure; + __u32 length; + __u32 handle; +}; + +struct fw_cdev_deallocate { + __u32 handle; +}; + +#define FW_CDEV_LONG_RESET 0 +#define FW_CDEV_SHORT_RESET 1 + +struct fw_cdev_initiate_bus_reset { + __u32 type; +}; + +struct fw_cdev_add_descriptor { + __u32 immediate; + __u32 key; + __u64 data; + __u32 length; + __u32 handle; +}; + +struct fw_cdev_remove_descriptor { + __u32 handle; +}; + +#define FW_CDEV_ISO_CONTEXT_TRANSMIT 0 +#define FW_CDEV_ISO_CONTEXT_RECEIVE 1 + +#define FW_CDEV_ISO_CONTEXT_MATCH_TAG0 1 +#define FW_CDEV_ISO_CONTEXT_MATCH_TAG1 2 +#define FW_CDEV_ISO_CONTEXT_MATCH_TAG2 4 +#define FW_CDEV_ISO_CONTEXT_MATCH_TAG3 8 +#define FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS 15 + +struct fw_cdev_create_iso_context { + __u32 type; + __u32 header_size; + __u32 channel; + __u32 speed; + __u64 closure; + __u32 handle; +}; + +struct fw_cdev_iso_packet { + __u16 payload_length; /* Length of indirect payload. */ + __u32 interrupt : 1; /* Generate interrupt on this packet */ + __u32 skip : 1; /* Set to not send packet at all. */ + __u32 tag : 2; + __u32 sy : 4; + __u32 header_length : 8; /* Length of immediate header. */ + __u32 header[0]; +}; + +struct fw_cdev_queue_iso { + __u64 packets; + __u64 data; + __u32 size; + __u32 handle; +}; + +struct fw_cdev_start_iso { + __s32 cycle; + __u32 sync; + __u32 tags; + __u32 handle; +}; + +struct fw_cdev_stop_iso { + __u32 handle; +}; + +#endif /* _LINUX_FIREWIRE_CDEV_H */ diff --git a/include/linux/firewire-constants.h b/include/linux/firewire-constants.h new file mode 100644 index 000000000000..b316770a43fd --- /dev/null +++ b/include/linux/firewire-constants.h @@ -0,0 +1,67 @@ +#ifndef _LINUX_FIREWIRE_CONSTANTS_H +#define _LINUX_FIREWIRE_CONSTANTS_H + +#define TCODE_WRITE_QUADLET_REQUEST 0x0 +#define TCODE_WRITE_BLOCK_REQUEST 0x1 +#define TCODE_WRITE_RESPONSE 0x2 +#define TCODE_READ_QUADLET_REQUEST 0x4 +#define TCODE_READ_BLOCK_REQUEST 0x5 +#define TCODE_READ_QUADLET_RESPONSE 0x6 +#define TCODE_READ_BLOCK_RESPONSE 0x7 +#define TCODE_CYCLE_START 0x8 +#define TCODE_LOCK_REQUEST 0x9 +#define TCODE_STREAM_DATA 0xa +#define TCODE_LOCK_RESPONSE 0xb + +#define EXTCODE_MASK_SWAP 0x1 +#define EXTCODE_COMPARE_SWAP 0x2 +#define EXTCODE_FETCH_ADD 0x3 +#define EXTCODE_LITTLE_ADD 0x4 +#define EXTCODE_BOUNDED_ADD 0x5 +#define EXTCODE_WRAP_ADD 0x6 +#define EXTCODE_VENDOR_DEPENDENT 0x7 + +/* Juju specific tcodes */ +#define TCODE_LOCK_MASK_SWAP (0x10 | EXTCODE_MASK_SWAP) +#define TCODE_LOCK_COMPARE_SWAP (0x10 | EXTCODE_COMPARE_SWAP) +#define TCODE_LOCK_FETCH_ADD (0x10 | EXTCODE_FETCH_ADD) +#define TCODE_LOCK_LITTLE_ADD (0x10 | EXTCODE_LITTLE_ADD) +#define TCODE_LOCK_BOUNDED_ADD (0x10 | EXTCODE_BOUNDED_ADD) +#define TCODE_LOCK_WRAP_ADD (0x10 | EXTCODE_WRAP_ADD) +#define TCODE_LOCK_VENDOR_DEPENDENT (0x10 | EXTCODE_VENDOR_DEPENDENT) + +#define RCODE_COMPLETE 0x0 +#define RCODE_CONFLICT_ERROR 0x4 +#define RCODE_DATA_ERROR 0x5 +#define RCODE_TYPE_ERROR 0x6 +#define RCODE_ADDRESS_ERROR 0x7 + +/* Juju specific rcodes */ +#define RCODE_SEND_ERROR 0x10 +#define RCODE_CANCELLED 0x11 +#define RCODE_BUSY 0x12 +#define RCODE_GENERATION 0x13 +#define RCODE_NO_ACK 0x14 + +#define SCODE_100 0x0 +#define SCODE_200 0x1 +#define SCODE_400 0x2 +#define SCODE_800 0x3 +#define SCODE_1600 0x4 +#define SCODE_3200 0x5 +#define SCODE_BETA 0x3 + +#define ACK_COMPLETE 0x1 +#define ACK_PENDING 0x2 +#define ACK_BUSY_X 0x4 +#define ACK_BUSY_A 0x5 +#define ACK_BUSY_B 0x6 +#define ACK_DATA_ERROR 0xd +#define ACK_TYPE_ERROR 0xe + +#define RETRY_1 0x00 +#define RETRY_X 0x01 +#define RETRY_A 0x02 +#define RETRY_B 0x03 + +#endif /* _LINUX_FIREWIRE_CONSTANTS_H */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 144b615f3a89..8645181fca0f 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -41,6 +41,16 @@ extern const char linux_proc_banner[]; #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +/** + * upper_32_bits - return bits 32-63 of a number + * @n: the number we're accessing + * + * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress + * the "right shift count >= width of type" warning when that quantity is + * 32-bits. + */ +#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) + #define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately */ #define KERN_CRIT "<2>" /* critical conditions */ diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index e30687bad075..d5bb1796e12b 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -50,13 +50,16 @@ struct page { spinlock_t ptl; #endif struct { /* SLUB uses */ - struct page *first_page; /* Compound pages */ + void **lockless_freelist; struct kmem_cache *slab; /* Pointer to slab */ }; + struct { + struct page *first_page; /* Compound pages */ + }; }; union { pgoff_t index; /* Our offset within mapping. */ - void *freelist; /* SLUB: pointer to free object */ + void *freelist; /* SLUB: freelist req. slab lock */ }; struct list_head lru; /* Pageout list, eg. active_list * protected by zone->lru_lock ! diff --git a/init/Kconfig b/init/Kconfig index e63a017c391e..322b1f8c21b3 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -505,6 +505,7 @@ config VM_EVENT_COUNTERS config SLUB_DEBUG default y bool "Enable SLUB debugging support" if EMBEDDED + depends on SLUB help SLUB has extensive debug support features. Disabling these can result in significant savings in code size. This also disables diff --git a/kernel/timer.c b/kernel/timer.c index 59a28b1752f8..a6c580ac084b 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -92,24 +92,24 @@ static DEFINE_PER_CPU(tvec_base_t *, tvec_bases) = &boot_tvec_bases; /* Functions below help us manage 'deferrable' flag */ static inline unsigned int tbase_get_deferrable(tvec_base_t *base) { - return (unsigned int)((unsigned long)base & TBASE_DEFERRABLE_FLAG); + return ((unsigned int)(unsigned long)base & TBASE_DEFERRABLE_FLAG); } static inline tvec_base_t *tbase_get_base(tvec_base_t *base) { - return (tvec_base_t *)((unsigned long)base & ~TBASE_DEFERRABLE_FLAG); + return ((tvec_base_t *)((unsigned long)base & ~TBASE_DEFERRABLE_FLAG)); } static inline void timer_set_deferrable(struct timer_list *timer) { - timer->base = (tvec_base_t *)((unsigned long)timer->base | - TBASE_DEFERRABLE_FLAG); + timer->base = ((tvec_base_t *)((unsigned long)(timer->base) | + TBASE_DEFERRABLE_FLAG)); } static inline void timer_set_base(struct timer_list *timer, tvec_base_t *new_base) { - timer->base = (tvec_base_t *)((unsigned long)new_base | + timer->base = (tvec_base_t *)((unsigned long)(new_base) | tbase_get_deferrable(timer->base)); } diff --git a/lib/Kconfig b/lib/Kconfig index 96d6e8ca8b70..2e7ae6b9215b 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -23,6 +23,14 @@ config CRC16 the kernel tree does. Such modules that use library CRC16 functions require M here. +config CRC_ITU_T + tristate "CRC ITU-T V.41 functions" + help + This option is provided for the case where no in-kernel-tree + modules require CRC ITU-T V.41 functions, but a module built outside + the kernel tree does. Such modules that use library CRC ITU-T V.41 + functions require M here. + config CRC32 tristate "CRC32 functions" default y diff --git a/lib/Makefile b/lib/Makefile index ae57f357fec0..1f65b4613e09 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -41,6 +41,7 @@ endif obj-$(CONFIG_BITREVERSE) += bitrev.o obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o obj-$(CONFIG_CRC16) += crc16.o +obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o obj-$(CONFIG_CRC32) += crc32.o obj-$(CONFIG_LIBCRC32C) += libcrc32c.o obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o diff --git a/lib/crc-itu-t.c b/lib/crc-itu-t.c new file mode 100644 index 000000000000..a63472b82416 --- /dev/null +++ b/lib/crc-itu-t.c @@ -0,0 +1,69 @@ +/* + * crc-itu-t.c + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/crc-itu-t.h> + +/** CRC table for the CRC ITU-T V.41 0x0x1021 (x^16 + x^12 + x^15 + 1) */ +const u16 crc_itu_t_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +EXPORT_SYMBOL(crc_itu_t_table); + +/** + * crc_itu_t - Compute the CRC-ITU-T for the data buffer + * + * @crc: previous CRC value + * @buffer: data pointer + * @len: number of bytes in the buffer + * + * Returns the updated CRC value + */ +u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len) +{ + while (len--) + crc = crc_itu_t_byte(crc, *buffer++); + return crc; +} +EXPORT_SYMBOL(crc_itu_t); + +MODULE_DESCRIPTION("CRC ITU-T V.41 calculations"); +MODULE_LICENSE("GPL"); + diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f9b5d6d5f4d6..ae96dd844432 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2284,7 +2284,7 @@ static int __meminit next_active_region_index_in_nid(int index, int nid) * was used and there are no special requirements, this is a convenient * alternative */ -int __init early_pfn_to_nid(unsigned long pfn) +int __meminit early_pfn_to_nid(unsigned long pfn) { int i; diff --git a/mm/slub.c b/mm/slub.c index bd2efae02bcd..b39c8a69a4ff 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -81,10 +81,14 @@ * PageActive The slab is used as a cpu cache. Allocations * may be performed from the slab. The slab is not * on any slab list and cannot be moved onto one. + * The cpu slab may be equipped with an additioanl + * lockless_freelist that allows lockless access to + * free objects in addition to the regular freelist + * that requires the slab lock. * * PageError Slab requires special handling due to debug * options set. This moves slab handling out of - * the fast path. + * the fast path and disables lockless freelists. */ static inline int SlabDebug(struct page *page) @@ -1014,6 +1018,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) set_freepointer(s, last, NULL); page->freelist = start; + page->lockless_freelist = NULL; page->inuse = 0; out: if (flags & __GFP_WAIT) @@ -1276,6 +1281,23 @@ static void putback_slab(struct kmem_cache *s, struct page *page) */ static void deactivate_slab(struct kmem_cache *s, struct page *page, int cpu) { + /* + * Merge cpu freelist into freelist. Typically we get here + * because both freelists are empty. So this is unlikely + * to occur. + */ + while (unlikely(page->lockless_freelist)) { + void **object; + + /* Retrieve object from cpu_freelist */ + object = page->lockless_freelist; + page->lockless_freelist = page->lockless_freelist[page->offset]; + + /* And put onto the regular freelist */ + object[page->offset] = page->freelist; + page->freelist = object; + page->inuse--; + } s->cpu_slab[cpu] = NULL; ClearPageActive(page); @@ -1322,47 +1344,46 @@ static void flush_all(struct kmem_cache *s) } /* - * slab_alloc is optimized to only modify two cachelines on the fast path - * (aside from the stack): + * Slow path. The lockless freelist is empty or we need to perform + * debugging duties. + * + * Interrupts are disabled. * - * 1. The page struct - * 2. The first cacheline of the object to be allocated. + * Processing is still very fast if new objects have been freed to the + * regular freelist. In that case we simply take over the regular freelist + * as the lockless freelist and zap the regular freelist. * - * The only other cache lines that are read (apart from code) is the - * per cpu array in the kmem_cache struct. + * If that is not working then we fall back to the partial lists. We take the + * first element of the freelist as the object to allocate now and move the + * rest of the freelist to the lockless freelist. * - * Fastpath is not possible if we need to get a new slab or have - * debugging enabled (which means all slabs are marked with SlabDebug) + * And if we were unable to get a new slab from the partial slab lists then + * we need to allocate a new slab. This is slowest path since we may sleep. */ -static void *slab_alloc(struct kmem_cache *s, - gfp_t gfpflags, int node, void *addr) +static void *__slab_alloc(struct kmem_cache *s, + gfp_t gfpflags, int node, void *addr, struct page *page) { - struct page *page; void **object; - unsigned long flags; - int cpu; + int cpu = smp_processor_id(); - local_irq_save(flags); - cpu = smp_processor_id(); - page = s->cpu_slab[cpu]; if (!page) goto new_slab; slab_lock(page); if (unlikely(node != -1 && page_to_nid(page) != node)) goto another_slab; -redo: +load_freelist: object = page->freelist; if (unlikely(!object)) goto another_slab; if (unlikely(SlabDebug(page))) goto debug; -have_object: - page->inuse++; - page->freelist = object[page->offset]; + object = page->freelist; + page->lockless_freelist = object[page->offset]; + page->inuse = s->objects; + page->freelist = NULL; slab_unlock(page); - local_irq_restore(flags); return object; another_slab: @@ -1370,11 +1391,11 @@ another_slab: new_slab: page = get_partial(s, gfpflags, node); - if (likely(page)) { + if (page) { have_slab: s->cpu_slab[cpu] = page; SetPageActive(page); - goto redo; + goto load_freelist; } page = new_slab(s, gfpflags, node); @@ -1397,7 +1418,7 @@ have_slab: discard_slab(s, page); page = s->cpu_slab[cpu]; slab_lock(page); - goto redo; + goto load_freelist; } /* New slab does not fit our expectations */ flush_slab(s, s->cpu_slab[cpu], cpu); @@ -1405,16 +1426,52 @@ have_slab: slab_lock(page); goto have_slab; } - local_irq_restore(flags); return NULL; debug: + object = page->freelist; if (!alloc_object_checks(s, page, object)) goto another_slab; if (s->flags & SLAB_STORE_USER) set_track(s, object, TRACK_ALLOC, addr); trace(s, page, object, 1); init_object(s, object, 1); - goto have_object; + + page->inuse++; + page->freelist = object[page->offset]; + slab_unlock(page); + return object; +} + +/* + * Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc) + * have the fastpath folded into their functions. So no function call + * overhead for requests that can be satisfied on the fastpath. + * + * The fastpath works by first checking if the lockless freelist can be used. + * If not then __slab_alloc is called for slow processing. + * + * Otherwise we can simply pick the next object from the lockless free list. + */ +static void __always_inline *slab_alloc(struct kmem_cache *s, + gfp_t gfpflags, int node, void *addr) +{ + struct page *page; + void **object; + unsigned long flags; + + local_irq_save(flags); + page = s->cpu_slab[smp_processor_id()]; + if (unlikely(!page || !page->lockless_freelist || + (node != -1 && page_to_nid(page) != node))) + + object = __slab_alloc(s, gfpflags, node, addr, page); + + else { + object = page->lockless_freelist; + page->lockless_freelist = object[page->offset]; + } + local_irq_restore(flags); + return object; } void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) @@ -1432,20 +1489,19 @@ EXPORT_SYMBOL(kmem_cache_alloc_node); #endif /* - * The fastpath only writes the cacheline of the page struct and the first - * cacheline of the object. + * Slow patch handling. This may still be called frequently since objects + * have a longer lifetime than the cpu slabs in most processing loads. * - * We read the cpu_slab cacheline to check if the slab is the per cpu - * slab for this processor. + * So we still attempt to reduce cache line usage. Just take the slab + * lock and free the item. If there is no additional partial page + * handling required then we can return immediately. */ -static void slab_free(struct kmem_cache *s, struct page *page, +static void __slab_free(struct kmem_cache *s, struct page *page, void *x, void *addr) { void *prior; void **object = (void *)x; - unsigned long flags; - local_irq_save(flags); slab_lock(page); if (unlikely(SlabDebug(page))) @@ -1475,7 +1531,6 @@ checks_ok: out_unlock: slab_unlock(page); - local_irq_restore(flags); return; slab_empty: @@ -1487,7 +1542,6 @@ slab_empty: slab_unlock(page); discard_slab(s, page); - local_irq_restore(flags); return; debug: @@ -1502,6 +1556,34 @@ debug: goto checks_ok; } +/* + * Fastpath with forced inlining to produce a kfree and kmem_cache_free that + * can perform fastpath freeing without additional function calls. + * + * The fastpath is only possible if we are freeing to the current cpu slab + * of this processor. This typically the case if we have just allocated + * the item before. + * + * If fastpath is not possible then fall back to __slab_free where we deal + * with all sorts of special processing. + */ +static void __always_inline slab_free(struct kmem_cache *s, + struct page *page, void *x, void *addr) +{ + void **object = (void *)x; + unsigned long flags; + + local_irq_save(flags); + if (likely(page == s->cpu_slab[smp_processor_id()] && + !SlabDebug(page))) { + object[page->offset] = page->lockless_freelist; + page->lockless_freelist = object; + } else + __slab_free(s, page, x, addr); + + local_irq_restore(flags); +} + void kmem_cache_free(struct kmem_cache *s, void *x) { struct page *page; @@ -2363,9 +2445,8 @@ void __init kmem_cache_init(void) register_cpu_notifier(&slab_notifier); #endif - if (nr_cpu_ids) /* Remove when nr_cpu_ids is fixed upstream ! */ - kmem_size = offsetof(struct kmem_cache, cpu_slab) - + nr_cpu_ids * sizeof(struct page *); + kmem_size = offsetof(struct kmem_cache, cpu_slab) + + nr_cpu_ids * sizeof(struct page *); printk(KERN_INFO "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d," " Processors=%d, Nodes=%d\n", diff --git a/net/Kconfig b/net/Kconfig index caeacd16656a..f3de72978ab6 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -218,6 +218,7 @@ config FIB_RULES bool menu "Wireless" + depends on !S390 source "net/wireless/Kconfig" source "net/mac80211/Kconfig" diff --git a/net/ax25/Kconfig b/net/ax25/Kconfig index 43dd86fca4d3..2a72aa96a568 100644 --- a/net/ax25/Kconfig +++ b/net/ax25/Kconfig @@ -3,7 +3,7 @@ # menuconfig HAMRADIO - depends on NET + depends on NET && !S390 bool "Amateur Radio support" help If you want to connect your Linux box to an amateur radio, answer Y diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 6929490d095a..7725da95a767 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -3,7 +3,7 @@ # menuconfig BT - depends on NET + depends on NET && !S390 tristate "Bluetooth subsystem support" help Bluetooth is low-cost, low-power, short-range wireless technology. diff --git a/net/irda/Kconfig b/net/irda/Kconfig index 9efb17ba48ac..c8671a7ffb3c 100644 --- a/net/irda/Kconfig +++ b/net/irda/Kconfig @@ -3,7 +3,7 @@ # menuconfig IRDA - depends on NET + depends on NET && !S390 tristate "IrDA (infrared) subsystem support" select CRC_CCITT ---help--- diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c index ce08b78647ce..90fa107a8af9 100644 --- a/net/rxrpc/ar-peer.c +++ b/net/rxrpc/ar-peer.c @@ -59,14 +59,14 @@ static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer) ret = ip_route_output_key(&rt, &fl); if (ret < 0) { - kleave(" [route err %d]", ret); + _leave(" [route err %d]", ret); return; } peer->if_mtu = dst_mtu(&rt->u.dst); dst_release(&rt->u.dst); - kleave(" [if_mtu %u]", peer->if_mtu); + _leave(" [if_mtu %u]", peer->if_mtu); } /* diff --git a/sound/Kconfig b/sound/Kconfig index 97532bbc2ccb..9ea473823418 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -2,6 +2,7 @@ # menu "Sound" + depends on HAS_IOMEM config SOUND tristate "Sound card support" |