From f4859acf155bf55eadfe8abc7087070ef066f212 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 9 Feb 2007 09:44:28 -0800 Subject: [PATCH] --- yaml --- r: 47305 b: refs/heads/master c: 2fd592e45b9c89d69e126f172d0f991e2af955e5 h: refs/heads/master i: 47303: 553ff697b0ed2ecc020f3f7670ca238b4148318d v: v3 --- [refs] | 2 +- trunk/Documentation/crypto/api-intro.txt | 4 + .../feature-removal-schedule.txt | 12 - .../sound/alsa/ALSA-Configuration.txt | 60 +- .../sound/alsa/DocBook/alsa-driver-api.tmpl | 4 +- .../alsa/DocBook/writing-an-alsa-driver.tmpl | 33 +- trunk/Documentation/sound/alsa/hda_codec.txt | 10 +- trunk/Documentation/sound/alsa/soc/DAI.txt | 56 + .../Documentation/sound/alsa/soc/clocking.txt | 51 + trunk/Documentation/sound/alsa/soc/codec.txt | 197 ++ trunk/Documentation/sound/alsa/soc/dapm.txt | 297 ++ .../Documentation/sound/alsa/soc/machine.txt | 113 + .../Documentation/sound/alsa/soc/overview.txt | 83 + .../Documentation/sound/alsa/soc/platform.txt | 58 + .../sound/alsa/soc/pops_clicks.txt | 52 + trunk/MAINTAINERS | 15 +- trunk/arch/avr32/boards/atstk1000/Makefile | 2 +- trunk/arch/avr32/boards/atstk1000/atstk1002.c | 53 +- trunk/arch/avr32/boards/atstk1000/spi.c | 27 - trunk/arch/avr32/kernel/cpu.c | 1 + trunk/arch/avr32/kernel/irq.c | 1 + trunk/arch/avr32/kernel/setup.c | 4 +- trunk/arch/avr32/lib/libgcc.h | 33 - trunk/arch/avr32/lib/longlong.h | 98 - trunk/arch/avr32/mach-at32ap/Makefile | 2 +- trunk/arch/avr32/mach-at32ap/at32ap7000.c | 60 +- trunk/arch/avr32/mach-at32ap/extint.c | 36 +- trunk/arch/avr32/mach-at32ap/pio.c | 255 +- trunk/arch/avr32/mm/cache.c | 32 +- trunk/arch/i386/kernel/hpet.c | 5 +- trunk/arch/i386/kernel/io_apic.c | 2 +- trunk/arch/i386/kernel/sysenter.c | 53 +- trunk/arch/i386/mm/pageattr.c | 2 +- trunk/arch/ia64/kernel/crash.c | 2 +- trunk/arch/ia64/kernel/smp.c | 4 +- trunk/arch/mips/dec/Makefile | 1 + trunk/arch/mips/dec/prom/identify.c | 3 + trunk/arch/mips/dec/setup.c | 2 + trunk/arch/mips/dec/tc.c | 95 + trunk/arch/powerpc/kernel/vdso.c | 104 +- trunk/arch/powerpc/platforms/cell/iommu.c | 5 +- trunk/arch/powerpc/platforms/celleb/pci.c | 12 +- .../arch/powerpc/platforms/celleb/scc_epci.c | 56 +- trunk/arch/powerpc/platforms/chrp/setup.c | 4 +- trunk/arch/powerpc/platforms/ps3/interrupt.c | 2 + trunk/arch/powerpc/platforms/ps3/system-bus.c | 2 + trunk/arch/powerpc/xmon/spu-dis.c | 2 +- trunk/arch/s390/defconfig | 3 +- trunk/arch/sh/kernel/vsyscall/vsyscall.c | 58 +- trunk/arch/x86_64/ia32/syscall32.c | 59 +- trunk/block/ll_rw_blk.c | 2 +- trunk/crypto/Kconfig | 31 + trunk/crypto/Makefile | 3 + trunk/crypto/algapi.c | 15 +- trunk/crypto/api.c | 80 +- trunk/crypto/blkcipher.c | 9 +- trunk/crypto/camellia.c | 1801 +++++++++++ trunk/crypto/cbc.c | 9 +- trunk/crypto/cipher.c | 447 +-- trunk/crypto/compress.c | 5 - trunk/crypto/digest.c | 24 +- trunk/crypto/ecb.c | 9 +- trunk/crypto/fcrypt.c | 423 +++ trunk/crypto/hash.c | 5 +- trunk/crypto/hmac.c | 9 +- trunk/crypto/internal.h | 27 +- trunk/crypto/lrw.c | 11 +- trunk/crypto/pcbc.c | 349 +++ trunk/crypto/tcrypt.c | 73 +- trunk/crypto/tcrypt.h | 538 +++- trunk/crypto/xcbc.c | 60 +- trunk/drivers/Makefile | 2 +- trunk/drivers/acpi/bay.c | 2 +- trunk/drivers/ata/ahci.c | 2 +- trunk/drivers/ata/sata_svw.c | 6 +- trunk/drivers/char/watchdog/machzwd.c | 2 +- trunk/drivers/crypto/geode-aes.c | 2 +- trunk/drivers/hwmon/ams/ams-input.c | 2 +- .../infiniband/ulp/iser/iser_initiator.c | 4 +- trunk/drivers/input/touchscreen/ucb1400_ts.c | 2 +- trunk/drivers/kvm/kvm_main.c | 63 +- trunk/drivers/kvm/mmu.c | 2 +- trunk/drivers/kvm/svm.c | 8 +- trunk/drivers/kvm/vmx.c | 2 +- trunk/drivers/macintosh/Kconfig | 2 +- trunk/drivers/macintosh/rack-meter.c | 6 +- trunk/drivers/md/bitmap.c | 22 +- trunk/drivers/md/raid5.c | 42 +- trunk/drivers/media/common/ir-keymaps.c | 1 - .../media/video/usbvision/usbvision-video.c | 2 +- trunk/drivers/misc/Kconfig | 2 +- trunk/drivers/misc/lkdtm.c | 4 +- trunk/drivers/mmc/Kconfig | 2 +- trunk/drivers/net/3c503.c | 3 +- trunk/drivers/net/Kconfig | 43 +- trunk/drivers/net/Makefile | 1 + trunk/drivers/net/ac3200.c | 3 +- trunk/drivers/net/atl1/Makefile | 2 + trunk/drivers/net/atl1/atl1.h | 283 ++ trunk/drivers/net/atl1/atl1_ethtool.c | 508 +++ trunk/drivers/net/atl1/atl1_hw.c | 718 +++++ trunk/drivers/net/atl1/atl1_hw.h | 951 ++++++ trunk/drivers/net/atl1/atl1_main.c | 2468 +++++++++++++++ trunk/drivers/net/atl1/atl1_param.c | 206 ++ trunk/drivers/net/bonding/bond_alb.c | 4 +- trunk/drivers/net/bonding/bond_main.c | 4 +- trunk/drivers/net/cxgb3/cxgb3_main.c | 86 +- trunk/drivers/net/cxgb3/cxgb3_offload.c | 4 +- trunk/drivers/net/defxx.c | 928 ++++-- trunk/drivers/net/defxx.h | 58 +- trunk/drivers/net/e2100.c | 3 +- trunk/drivers/net/es3210.c | 2 +- trunk/drivers/net/macsonic.c | 1 + trunk/drivers/net/mv643xx_eth.c | 1 - trunk/drivers/net/r8169.c | 4 +- trunk/drivers/net/s2io.c | 2 +- trunk/drivers/net/s2io.h | 6 +- trunk/drivers/net/slip.c | 5 +- trunk/drivers/net/smc-mca.c | 3 +- trunk/drivers/net/smc-ultra.c | 3 +- trunk/drivers/net/smc-ultra32.c | 3 +- trunk/drivers/net/spider_net.c | 2 +- trunk/drivers/net/tg3.c | 2 +- trunk/drivers/net/ucc_geth.c | 79 +- trunk/drivers/net/ucc_geth_phy.c | 2 + trunk/drivers/net/wan/pc300too.c | 16 +- trunk/drivers/net/wd.c | 2 +- trunk/drivers/pcmcia/m32r_pcc.c | 2 +- trunk/drivers/rtc/rtc-dev.c | 2 +- trunk/drivers/rtc/rtc-pcf8563.c | 40 +- trunk/drivers/s390/char/monreader.c | 218 +- trunk/drivers/s390/char/vmlogrdr.c | 279 +- trunk/drivers/s390/net/Kconfig | 7 - trunk/drivers/s390/net/Makefile | 1 - trunk/drivers/s390/net/iucv.c | 2540 --------------- trunk/drivers/s390/net/iucv.h | 849 ----- trunk/drivers/s390/net/netiucv.c | 1314 ++++---- trunk/drivers/s390/net/smsgiucv.c | 147 +- trunk/drivers/scsi/NCR53C9x.c | 8 +- trunk/drivers/scsi/NCR53C9x.h | 2 +- trunk/drivers/scsi/blz1230.c | 3 +- trunk/drivers/scsi/blz2060.c | 2 +- trunk/drivers/scsi/cyberstorm.c | 2 +- trunk/drivers/scsi/cyberstormII.c | 2 +- trunk/drivers/scsi/dec_esp.c | 355 ++- trunk/drivers/scsi/fastlane.c | 2 +- trunk/drivers/scsi/iscsi_tcp.c | 2 +- trunk/drivers/scsi/jazz_esp.c | 2 +- trunk/drivers/scsi/libiscsi.c | 40 +- trunk/drivers/scsi/mac_esp.c | 2 +- trunk/drivers/scsi/mca_53c9x.c | 2 +- trunk/drivers/scsi/oktagon_esp.c | 2 +- trunk/drivers/scsi/osst.c | 8 +- trunk/drivers/scsi/osst.h | 68 +- trunk/drivers/scsi/sun3x_esp.c | 2 +- trunk/drivers/serial/uartlite.c | 6 +- trunk/drivers/tc/Makefile | 2 +- trunk/drivers/tc/tc-driver.c | 110 + trunk/drivers/tc/tc.c | 339 +- trunk/drivers/usb/host/ehci-ps3.c | 2 +- trunk/drivers/usb/host/ehci.h | 12 +- trunk/drivers/usb/host/ohci-ps3.c | 2 +- trunk/drivers/usb/host/ohci.h | 12 +- trunk/drivers/usb/net/gl620a.c | 26 +- trunk/drivers/usb/serial/cp2101.c | 8 +- trunk/drivers/video/Kconfig | 8 +- trunk/drivers/video/pmag-ba-fb.c | 95 +- trunk/drivers/video/pmagb-b-fb.c | 98 +- trunk/fs/9p/vfs_inode.c | 7 +- trunk/fs/dlm/lowcomms-tcp.c | 23 +- trunk/fs/ecryptfs/crypto.c | 4 +- trunk/fs/ecryptfs/ecryptfs_kernel.h | 1 - trunk/fs/hugetlbfs/inode.c | 5 +- trunk/fs/ufs/dir.c | 21 +- trunk/fs/ufs/super.c | 5 +- trunk/include/asm-alpha/io.h | 9 - trunk/include/asm-arm/arch-ixp4xx/io.h | 3 - trunk/include/asm-arm/io.h | 5 - .../asm-avr32/arch-at32ap/at32ap7000.h | 2 + trunk/include/asm-avr32/arch-at32ap/gpio.h | 27 + trunk/include/asm-avr32/arch-at32ap/irq.h | 14 + trunk/include/asm-avr32/arch-at32ap/portmux.h | 8 +- trunk/include/asm-avr32/checksum.h | 2 +- trunk/include/asm-avr32/dma-mapping.h | 8 + trunk/include/asm-avr32/gpio.h | 6 + trunk/include/asm-avr32/irq.h | 8 +- trunk/include/asm-avr32/posix_types.h | 2 +- trunk/include/asm-avr32/uaccess.h | 6 - trunk/include/asm-cris/io.h | 5 - trunk/include/asm-i386/io.h | 6 - trunk/include/asm-mips/dec/system.h | 3 +- trunk/include/asm-mips/dec/tc.h | 41 - trunk/include/asm-mips/dec/tcinfo.h | 47 - trunk/include/asm-mips/dec/tcmodule.h | 39 - trunk/include/asm-mips/io.h | 6 - trunk/include/asm-parisc/io.h | 9 - trunk/include/asm-ppc/io.h | 2 - trunk/include/asm-x86_64/io.h | 6 - trunk/include/asm-x86_64/proto.h | 1 - trunk/include/crypto/algapi.h | 24 +- trunk/include/linux/atmarp.h | 2 - trunk/include/linux/crypto.h | 148 +- trunk/include/linux/eisa.h | 10 + trunk/include/linux/gfp.h | 2 +- trunk/include/linux/i2c-id.h | 2 + trunk/include/linux/if_packet.h | 10 + trunk/include/linux/mm.h | 3 + trunk/include/linux/net.h | 2 +- trunk/include/linux/netdevice.h | 2 +- trunk/include/linux/netfilter/Kbuild | 1 + .../linux/netfilter/nf_conntrack_sane.h | 21 + .../linux/netfilter/nf_conntrack_tcp.h | 4 +- trunk/include/linux/netfilter/xt_TCPMSS.h | 10 + trunk/include/linux/netfilter_ipv4/ip_nat.h | 1 + .../include/linux/netfilter_ipv4/ip_tables.h | 22 +- .../include/linux/netfilter_ipv4/ipt_TCPMSS.h | 7 +- .../include/linux/netfilter_ipv6/ip6_tables.h | 35 +- trunk/include/linux/netfilter_ipv6/ip6t_mh.h | 15 + trunk/include/linux/pagemap.h | 2 - trunk/include/linux/pci_ids.h | 2 + trunk/include/linux/pfkeyv2.h | 4 +- trunk/include/linux/raid/bitmap.h | 1 + trunk/include/linux/socket.h | 4 +- trunk/include/linux/sunrpc/svcsock.h | 2 +- trunk/include/linux/sysctl.h | 3 +- trunk/include/linux/tc.h | 141 + trunk/include/linux/tcp.h | 2 +- trunk/include/linux/ufs_fs.h | 1 + trunk/include/linux/wanrouter.h | 8 - trunk/include/linux/xfrm.h | 19 + trunk/include/net/inet_hashtables.h | 10 +- trunk/include/net/iucv/af_iucv.h | 106 + trunk/include/net/iucv/iucv.h | 415 +++ trunk/include/net/netfilter/nf_conntrack.h | 2 + trunk/include/net/netfilter/nf_nat.h | 1 + trunk/include/net/route.h | 5 +- trunk/include/net/tcp.h | 5 +- trunk/include/net/x25.h | 18 + trunk/include/net/xfrm.h | 47 + trunk/include/scsi/iscsi_proto.h | 46 +- trunk/include/sound/ac97_codec.h | 4 +- trunk/include/sound/ad1848.h | 2 +- trunk/include/sound/ak4114.h | 3 +- trunk/include/sound/ak4117.h | 2 +- trunk/include/sound/ak4xxx-adda.h | 6 +- trunk/include/sound/control.h | 5 +- trunk/include/sound/core.h | 62 +- trunk/include/sound/emu10k1.h | 418 ++- trunk/include/sound/pcm.h | 4 + trunk/include/sound/pt2258.h | 37 + trunk/include/sound/sb16_csp.h | 14 + trunk/include/sound/snd_wavefront.h | 2 + trunk/include/sound/soc-dapm.h | 286 ++ trunk/include/sound/soc.h | 461 +++ trunk/include/sound/typedefs.h | 173 -- trunk/include/sound/version.h | 4 +- trunk/include/sound/vx_core.h | 2 +- trunk/include/sound/ymfpci.h | 6 +- trunk/mm/filemap.c | 20 - trunk/mm/hugetlb.c | 2 + trunk/mm/mmap.c | 72 + trunk/mm/page_alloc.c | 7 +- trunk/net/Kconfig | 1 + trunk/net/Makefile | 1 + trunk/net/atm/common.c | 3 +- trunk/net/bluetooth/hidp/hidp.h | 2 +- trunk/net/bluetooth/hidp/sock.c | 2 +- trunk/net/bridge/br_netfilter.c | 29 +- trunk/net/bridge/br_netlink.c | 14 +- trunk/net/bridge/netfilter/ebt_ip.c | 1 + trunk/net/bridge/netfilter/ebt_log.c | 1 + trunk/net/core/dev.c | 13 +- trunk/net/core/dst.c | 9 +- trunk/net/core/fib_rules.c | 14 +- trunk/net/core/neighbour.c | 29 +- trunk/net/core/rtnetlink.c | 23 +- trunk/net/dccp/ccids/ccid3.c | 5 +- trunk/net/dccp/ipv4.c | 2 +- trunk/net/dccp/ipv6.c | 2 +- trunk/net/dccp/proto.c | 4 +- trunk/net/decnet/dn_dev.c | 14 +- trunk/net/decnet/dn_table.c | 11 +- trunk/net/ipv4/af_inet.c | 2 +- trunk/net/ipv4/datagram.c | 2 +- trunk/net/ipv4/devinet.c | 14 +- trunk/net/ipv4/fib_semantics.c | 14 +- trunk/net/ipv4/igmp.c | 2 + trunk/net/ipv4/inet_diag.c | 19 +- trunk/net/ipv4/inet_hashtables.c | 2 +- trunk/net/ipv4/inet_timewait_sock.c | 4 +- trunk/net/ipv4/ip_gre.c | 3 +- trunk/net/ipv4/ipip.c | 3 +- trunk/net/ipv4/netfilter/Kconfig | 26 - trunk/net/ipv4/netfilter/Makefile | 1 - .../ipv4/netfilter/ip_conntrack_proto_tcp.c | 40 +- trunk/net/ipv4/netfilter/ip_nat_core.c | 12 +- trunk/net/ipv4/netfilter/ip_nat_helper.c | 2 +- trunk/net/ipv4/netfilter/ip_nat_proto_tcp.c | 5 + trunk/net/ipv4/netfilter/ip_nat_proto_udp.c | 5 + trunk/net/ipv4/netfilter/ip_nat_rule.c | 32 +- trunk/net/ipv4/netfilter/ip_tables.c | 40 +- trunk/net/ipv4/netfilter/ipt_CLUSTERIP.c | 15 +- trunk/net/ipv4/netfilter/ipt_ECN.c | 13 +- trunk/net/ipv4/netfilter/ipt_LOG.c | 16 +- trunk/net/ipv4/netfilter/ipt_MASQUERADE.c | 9 +- trunk/net/ipv4/netfilter/ipt_NETMAP.c | 8 +- trunk/net/ipv4/netfilter/ipt_REDIRECT.c | 8 +- trunk/net/ipv4/netfilter/ipt_REJECT.c | 12 +- trunk/net/ipv4/netfilter/ipt_SAME.c | 8 +- trunk/net/ipv4/netfilter/ipt_TCPMSS.c | 207 -- trunk/net/ipv4/netfilter/ipt_TOS.c | 11 +- trunk/net/ipv4/netfilter/ipt_TTL.c | 11 +- trunk/net/ipv4/netfilter/ipt_ULOG.c | 18 +- trunk/net/ipv4/netfilter/ipt_addrtype.c | 9 +- trunk/net/ipv4/netfilter/ipt_ah.c | 10 +- trunk/net/ipv4/netfilter/ipt_ecn.c | 10 +- trunk/net/ipv4/netfilter/ipt_iprange.c | 10 +- trunk/net/ipv4/netfilter/ipt_owner.c | 9 +- trunk/net/ipv4/netfilter/ipt_recent.c | 12 +- trunk/net/ipv4/netfilter/ipt_tos.c | 10 +- trunk/net/ipv4/netfilter/ipt_ttl.c | 11 +- trunk/net/ipv4/netfilter/iptable_filter.c | 2 +- trunk/net/ipv4/netfilter/iptable_mangle.c | 2 +- trunk/net/ipv4/netfilter/iptable_raw.c | 2 +- trunk/net/ipv4/netfilter/nf_nat_core.c | 12 +- trunk/net/ipv4/netfilter/nf_nat_helper.c | 2 +- trunk/net/ipv4/netfilter/nf_nat_proto_tcp.c | 4 + trunk/net/ipv4/netfilter/nf_nat_proto_udp.c | 4 + trunk/net/ipv4/netfilter/nf_nat_rule.c | 8 +- trunk/net/ipv4/netfilter/nf_nat_standalone.c | 6 - trunk/net/ipv4/raw.c | 2 +- trunk/net/ipv4/route.c | 5 +- trunk/net/ipv4/tcp.c | 7 +- trunk/net/ipv4/tcp_input.c | 105 +- trunk/net/ipv4/tcp_ipv4.c | 18 +- trunk/net/ipv4/tcp_output.c | 3 +- trunk/net/ipv4/udp.c | 2 +- trunk/net/ipv4/xfrm4_mode_tunnel.c | 57 +- trunk/net/ipv4/xfrm4_policy.c | 51 +- trunk/net/ipv4/xfrm4_state.c | 1 + trunk/net/ipv6/addrconf.c | 70 +- trunk/net/ipv6/datagram.c | 2 +- trunk/net/ipv6/inet6_hashtables.c | 4 +- trunk/net/ipv6/ip6_tunnel.c | 3 +- trunk/net/ipv6/mcast.c | 2 + trunk/net/ipv6/mip6.c | 26 - trunk/net/ipv6/netfilter/Kconfig | 8 + trunk/net/ipv6/netfilter/Makefile | 1 + trunk/net/ipv6/netfilter/ip6_tables.c | 12 +- trunk/net/ipv6/netfilter/ip6t_HL.c | 17 +- trunk/net/ipv6/netfilter/ip6t_LOG.c | 15 +- trunk/net/ipv6/netfilter/ip6t_REJECT.c | 10 +- trunk/net/ipv6/netfilter/ip6t_ah.c | 8 +- trunk/net/ipv6/netfilter/ip6t_eui64.c | 8 +- trunk/net/ipv6/netfilter/ip6t_frag.c | 8 +- trunk/net/ipv6/netfilter/ip6t_hbh.c | 1 + trunk/net/ipv6/netfilter/ip6t_hl.c | 11 +- trunk/net/ipv6/netfilter/ip6t_ipv6header.c | 8 +- trunk/net/ipv6/netfilter/ip6t_mh.c | 108 + trunk/net/ipv6/netfilter/ip6t_owner.c | 8 +- trunk/net/ipv6/netfilter/ip6t_rt.c | 8 +- trunk/net/ipv6/netfilter/ip6table_filter.c | 21 +- trunk/net/ipv6/netfilter/ip6table_mangle.c | 21 +- trunk/net/ipv6/netfilter/ip6table_raw.c | 19 - trunk/net/ipv6/raw.c | 15 +- trunk/net/ipv6/route.c | 33 +- trunk/net/ipv6/sit.c | 3 +- trunk/net/ipv6/tcp_ipv6.c | 2 +- trunk/net/ipv6/udp.c | 2 +- trunk/net/ipv6/xfrm6_mode_tunnel.c | 42 +- trunk/net/ipv6/xfrm6_policy.c | 46 +- trunk/net/ipv6/xfrm6_state.c | 1 + trunk/net/ipx/af_ipx.c | 24 +- trunk/net/irda/irias_object.c | 40 + trunk/net/irda/irlan/irlan_common.c | 23 +- trunk/net/iucv/Kconfig | 15 + trunk/net/iucv/Makefile | 6 + trunk/net/iucv/af_iucv.c | 1077 +++++++ trunk/net/iucv/iucv.c | 1619 ++++++++++ trunk/net/key/af_key.c | 422 +++ trunk/net/netfilter/Kconfig | 39 + trunk/net/netfilter/Makefile | 2 + trunk/net/netfilter/nf_conntrack_proto_tcp.c | 40 +- trunk/net/netfilter/nf_conntrack_sane.c | 242 ++ trunk/net/netfilter/xt_CLASSIFY.c | 4 +- trunk/net/netfilter/xt_CONNMARK.c | 5 +- trunk/net/netfilter/xt_CONNSECMARK.c | 6 +- trunk/net/netfilter/xt_MARK.c | 8 +- trunk/net/netfilter/xt_SECMARK.c | 4 +- trunk/net/netfilter/xt_TCPMSS.c | 296 ++ trunk/net/netfilter/xt_hashlimit.c | 1 + trunk/net/packet/af_packet.c | 79 +- trunk/net/sched/act_ipt.c | 2 +- trunk/net/sched/sch_generic.c | 2 +- trunk/net/sched/sch_prio.c | 15 + trunk/net/sched/sch_sfq.c | 2 + trunk/net/socket.c | 29 +- trunk/net/sunrpc/svc.c | 4 +- trunk/net/sunrpc/svcsock.c | 52 +- trunk/net/wanrouter/wanmain.c | 17 +- trunk/net/x25/Makefile | 2 +- trunk/net/x25/af_x25.c | 32 +- trunk/net/x25/sysctl_net_x25.c | 8 + trunk/net/x25/x25_dev.c | 13 +- trunk/net/x25/x25_forward.c | 163 + trunk/net/x25/x25_proc.c | 98 + trunk/net/x25/x25_route.c | 3 + trunk/net/xfrm/Kconfig | 26 + trunk/net/xfrm/xfrm_algo.c | 17 + trunk/net/xfrm/xfrm_policy.c | 231 ++ trunk/net/xfrm/xfrm_state.c | 184 +- trunk/net/xfrm/xfrm_user.c | 173 ++ trunk/sound/Kconfig | 2 + trunk/sound/Makefile | 2 +- trunk/sound/ac97_bus.c | 4 + trunk/sound/aoa/aoa.h | 2 +- trunk/sound/aoa/codecs/snd-aoa-codec-onyx.c | 11 +- trunk/sound/aoa/core/snd-aoa-alsa.c | 5 +- trunk/sound/aoa/core/snd-aoa-alsa.h | 2 +- trunk/sound/aoa/core/snd-aoa-core.c | 4 +- .../sound/aoa/fabrics/snd-aoa-fabric-layout.c | 13 +- trunk/sound/aoa/soundbus/i2sbus/i2sbus-core.c | 22 +- trunk/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | 407 +-- trunk/sound/aoa/soundbus/i2sbus/i2sbus.h | 6 + trunk/sound/arm/aaci.h | 2 +- trunk/sound/core/control.c | 42 +- trunk/sound/core/control_compat.c | 5 +- trunk/sound/core/device.c | 24 +- trunk/sound/core/hwdep.c | 19 +- trunk/sound/core/init.c | 22 +- trunk/sound/core/memalloc.c | 10 +- trunk/sound/core/misc.c | 28 + trunk/sound/core/pcm.c | 50 +- trunk/sound/core/pcm_lib.c | 5 + trunk/sound/core/pcm_memory.c | 23 + trunk/sound/core/rawmidi.c | 29 +- trunk/sound/core/seq/seq_clientmgr.c | 14 +- trunk/sound/core/seq/seq_device.c | 25 +- trunk/sound/core/seq/seq_ports.c | 51 +- trunk/sound/core/seq/seq_virmidi.c | 4 +- trunk/sound/core/sound.c | 15 +- trunk/sound/core/timer.c | 80 +- trunk/sound/drivers/Kconfig | 11 + trunk/sound/drivers/Makefile | 2 + trunk/sound/drivers/dummy.c | 2 +- trunk/sound/drivers/portman2x4.c | 876 ++++++ trunk/sound/drivers/serial-u16550.c | 221 +- trunk/sound/drivers/vx/vx_mixer.c | 2 +- trunk/sound/i2c/Makefile | 1 + trunk/sound/i2c/other/Makefile | 4 +- trunk/sound/i2c/other/ak4114.c | 29 +- trunk/sound/i2c/other/ak4117.c | 2 +- trunk/sound/i2c/other/ak4xxx-adda.c | 110 +- trunk/sound/i2c/other/pt2258.c | 233 ++ trunk/sound/isa/Kconfig | 2 + trunk/sound/isa/ad1816a/ad1816a_lib.c | 10 +- trunk/sound/isa/ad1848/ad1848_lib.c | 6 +- trunk/sound/isa/gus/gus_main.c | 6 +- trunk/sound/isa/opl3sa2.c | 4 +- trunk/sound/isa/sb/sb16_csp.c | 61 +- trunk/sound/isa/wavefront/wavefront.c | 1 + trunk/sound/isa/wavefront/wavefront_fx.c | 812 +---- trunk/sound/isa/wavefront/yss225.c | 2739 +++++++++++++++++ trunk/sound/pci/Kconfig | 30 +- trunk/sound/pci/ac97/ac97_codec.c | 64 +- trunk/sound/pci/ac97/ac97_patch.c | 549 +++- trunk/sound/pci/ac97/ac97_patch.h | 1 + trunk/sound/pci/ac97/ak4531_codec.c | 6 +- trunk/sound/pci/als300.c | 6 +- trunk/sound/pci/atiixp.c | 31 +- trunk/sound/pci/atiixp_modem.c | 2 +- trunk/sound/pci/ca0106/ca0106_main.c | 21 +- trunk/sound/pci/ca0106/ca0106_mixer.c | 50 +- trunk/sound/pci/cs4281.c | 2 +- trunk/sound/pci/echoaudio/darla20.c | 1 + trunk/sound/pci/echoaudio/darla24.c | 1 + trunk/sound/pci/echoaudio/echo3g.c | 1 + trunk/sound/pci/echoaudio/echo3g_dsp.c | 2 +- trunk/sound/pci/echoaudio/echoaudio.c | 18 +- trunk/sound/pci/echoaudio/gina20.c | 1 + trunk/sound/pci/echoaudio/gina24.c | 1 + trunk/sound/pci/echoaudio/indigo.c | 1 + trunk/sound/pci/echoaudio/indigodj.c | 1 + trunk/sound/pci/echoaudio/indigoio.c | 1 + trunk/sound/pci/echoaudio/layla20.c | 1 + trunk/sound/pci/echoaudio/layla24.c | 1 + trunk/sound/pci/echoaudio/mia.c | 1 + trunk/sound/pci/echoaudio/mona.c | 1 + trunk/sound/pci/emu10k1/emu10k1_main.c | 616 +++- trunk/sound/pci/emu10k1/emu10k1x.c | 6 +- trunk/sound/pci/emu10k1/emufx.c | 204 +- trunk/sound/pci/emu10k1/emumixer.c | 745 ++++- trunk/sound/pci/emu10k1/emupcm.c | 147 +- trunk/sound/pci/emu10k1/emuproc.c | 34 +- trunk/sound/pci/emu10k1/io.c | 104 + trunk/sound/pci/emu10k1/p16v.c | 14 +- trunk/sound/pci/emu10k1/p17v.h | 47 + trunk/sound/pci/emu10k1/voice.c | 2 +- trunk/sound/pci/ens1370.c | 154 +- trunk/sound/pci/es1938.c | 2 +- trunk/sound/pci/fm801.c | 2 +- trunk/sound/pci/hda/Makefile | 11 +- trunk/sound/pci/hda/hda_codec.c | 68 +- trunk/sound/pci/hda/hda_intel.c | 33 +- trunk/sound/pci/hda/hda_local.h | 12 +- trunk/sound/pci/hda/hda_patch.h | 6 + trunk/sound/pci/hda/patch_analog.c | 165 +- trunk/sound/pci/hda/patch_cmedia.c | 24 +- trunk/sound/pci/hda/patch_conexant.c | 1311 ++++++++ trunk/sound/pci/hda/patch_realtek.c | 2523 ++++++++++++--- trunk/sound/pci/hda/patch_sigmatel.c | 692 +++-- trunk/sound/pci/hda/patch_via.c | 1396 +++++++++ trunk/sound/pci/ice1712/Makefile | 2 +- trunk/sound/pci/ice1712/amp.c | 4 +- trunk/sound/pci/ice1712/amp.h | 2 +- trunk/sound/pci/ice1712/aureon.c | 186 +- trunk/sound/pci/ice1712/aureon.h | 6 +- trunk/sound/pci/ice1712/delta.c | 34 +- trunk/sound/pci/ice1712/delta.h | 2 +- trunk/sound/pci/ice1712/ews.c | 24 +- trunk/sound/pci/ice1712/ews.h | 2 +- trunk/sound/pci/ice1712/hoontech.c | 7 +- trunk/sound/pci/ice1712/hoontech.h | 2 +- trunk/sound/pci/ice1712/ice1712.c | 74 +- trunk/sound/pci/ice1712/ice1712.h | 18 +- trunk/sound/pci/ice1712/ice1724.c | 78 +- trunk/sound/pci/ice1712/juli.c | 36 +- trunk/sound/pci/ice1712/juli.h | 2 +- trunk/sound/pci/ice1712/phase.c | 76 +- trunk/sound/pci/ice1712/phase.h | 2 +- trunk/sound/pci/ice1712/pontis.c | 42 +- trunk/sound/pci/ice1712/pontis.h | 2 +- trunk/sound/pci/ice1712/prodigy192.c | 40 +- trunk/sound/pci/ice1712/prodigy192.h | 2 +- trunk/sound/pci/ice1712/revo.c | 372 ++- trunk/sound/pci/ice1712/revo.h | 13 +- trunk/sound/pci/ice1712/vt1720_mobo.c | 59 +- trunk/sound/pci/ice1712/vt1720_mobo.h | 2 +- trunk/sound/pci/ice1712/wtm.c | 542 ++++ trunk/sound/pci/ice1712/wtm.h | 20 + trunk/sound/pci/intel8x0.c | 208 +- trunk/sound/pci/intel8x0m.c | 120 +- trunk/sound/pci/korg1212/korg1212.c | 45 +- trunk/sound/pci/maestro3.c | 373 +-- trunk/sound/pci/mixart/mixart_mixer.c | 4 +- trunk/sound/pci/nm256/nm256.c | 56 +- trunk/sound/pci/pcxhr/pcxhr_mixer.c | 6 +- trunk/sound/pci/rme9652/hdsp.c | 38 + trunk/sound/pci/rme9652/hdspm.c | 1320 ++++++-- trunk/sound/pci/trident/trident_main.c | 4 +- trunk/sound/pci/via82xx.c | 134 +- trunk/sound/pci/via82xx_modem.c | 2 +- trunk/sound/pci/vx222/vx222.c | 4 +- trunk/sound/pci/vx222/vx222_ops.c | 2 +- trunk/sound/pci/ymfpci/ymfpci_image.h | 6 +- trunk/sound/pci/ymfpci/ymfpci_main.c | 171 +- trunk/sound/pcmcia/vx/vxp_mixer.c | 2 +- trunk/sound/pcmcia/vx/vxpocket.c | 2 +- trunk/sound/soc/Kconfig | 32 + trunk/sound/soc/Makefile | 4 + trunk/sound/soc/at91/Kconfig | 32 + trunk/sound/soc/at91/Makefile | 11 + trunk/sound/soc/at91/at91-i2s.c | 720 +++++ trunk/sound/soc/at91/at91-i2s.h | 27 + trunk/sound/soc/at91/at91-pcm.c | 432 +++ trunk/sound/soc/at91/at91-pcm.h | 72 + trunk/sound/soc/at91/eti_b1_wm8731.c | 375 +++ trunk/sound/soc/codecs/Kconfig | 15 + trunk/sound/soc/codecs/Makefile | 9 + trunk/sound/soc/codecs/ac97.c | 156 + trunk/sound/soc/codecs/ac97.h | 18 + trunk/sound/soc/codecs/wm8731.c | 758 +++++ trunk/sound/soc/codecs/wm8731.h | 44 + trunk/sound/soc/codecs/wm8750.c | 1049 +++++++ trunk/sound/soc/codecs/wm8750.h | 67 + trunk/sound/soc/codecs/wm9712.c | 771 +++++ trunk/sound/soc/codecs/wm9712.h | 14 + trunk/sound/soc/pxa/Kconfig | 60 + trunk/sound/soc/pxa/Makefile | 20 + trunk/sound/soc/pxa/corgi.c | 383 +++ trunk/sound/soc/pxa/poodle.c | 352 +++ trunk/sound/soc/pxa/pxa2xx-ac97.c | 431 +++ trunk/sound/soc/pxa/pxa2xx-ac97.h | 22 + trunk/sound/soc/pxa/pxa2xx-i2s.c | 318 ++ trunk/sound/soc/pxa/pxa2xx-i2s.h | 20 + trunk/sound/soc/pxa/pxa2xx-pcm.c | 372 +++ trunk/sound/soc/pxa/pxa2xx-pcm.h | 34 + trunk/sound/soc/pxa/spitz.c | 394 +++ trunk/sound/soc/pxa/tosa.c | 289 ++ trunk/sound/soc/soc-core.c | 1587 ++++++++++ trunk/sound/soc/soc-dapm.c | 1323 ++++++++ trunk/sound/sparc/dbri.c | 2 +- trunk/sound/usb/usbaudio.c | 189 +- trunk/sound/usb/usbaudio.h | 1 + trunk/sound/usb/usbquirks.h | 32 +- 595 files changed, 46909 insertions(+), 11890 deletions(-) create mode 100644 trunk/Documentation/sound/alsa/soc/DAI.txt create mode 100644 trunk/Documentation/sound/alsa/soc/clocking.txt create mode 100644 trunk/Documentation/sound/alsa/soc/codec.txt create mode 100644 trunk/Documentation/sound/alsa/soc/dapm.txt create mode 100644 trunk/Documentation/sound/alsa/soc/machine.txt create mode 100644 trunk/Documentation/sound/alsa/soc/overview.txt create mode 100644 trunk/Documentation/sound/alsa/soc/platform.txt create mode 100644 trunk/Documentation/sound/alsa/soc/pops_clicks.txt delete mode 100644 trunk/arch/avr32/boards/atstk1000/spi.c delete mode 100644 trunk/arch/avr32/lib/libgcc.h delete mode 100644 trunk/arch/avr32/lib/longlong.h create mode 100644 trunk/arch/mips/dec/tc.c create mode 100644 trunk/crypto/camellia.c create mode 100644 trunk/crypto/fcrypt.c create mode 100644 trunk/crypto/pcbc.c create mode 100644 trunk/drivers/net/atl1/Makefile create mode 100644 trunk/drivers/net/atl1/atl1.h create mode 100644 trunk/drivers/net/atl1/atl1_ethtool.c create mode 100644 trunk/drivers/net/atl1/atl1_hw.c create mode 100644 trunk/drivers/net/atl1/atl1_hw.h create mode 100644 trunk/drivers/net/atl1/atl1_main.c create mode 100644 trunk/drivers/net/atl1/atl1_param.c delete mode 100644 trunk/drivers/s390/net/iucv.c delete mode 100644 trunk/drivers/s390/net/iucv.h create mode 100644 trunk/drivers/tc/tc-driver.c create mode 100644 trunk/include/asm-avr32/arch-at32ap/gpio.h create mode 100644 trunk/include/asm-avr32/arch-at32ap/irq.h create mode 100644 trunk/include/asm-avr32/gpio.h delete mode 100644 trunk/include/asm-mips/dec/tc.h delete mode 100644 trunk/include/asm-mips/dec/tcinfo.h delete mode 100644 trunk/include/asm-mips/dec/tcmodule.h create mode 100644 trunk/include/linux/netfilter/nf_conntrack_sane.h create mode 100644 trunk/include/linux/netfilter/xt_TCPMSS.h create mode 100644 trunk/include/linux/netfilter_ipv6/ip6t_mh.h create mode 100644 trunk/include/linux/tc.h create mode 100644 trunk/include/net/iucv/af_iucv.h create mode 100644 trunk/include/net/iucv/iucv.h create mode 100644 trunk/include/sound/pt2258.h create mode 100644 trunk/include/sound/soc-dapm.h create mode 100644 trunk/include/sound/soc.h delete mode 100644 trunk/include/sound/typedefs.h delete mode 100644 trunk/net/ipv4/netfilter/ipt_TCPMSS.c create mode 100644 trunk/net/ipv6/netfilter/ip6t_mh.c create mode 100644 trunk/net/iucv/Kconfig create mode 100644 trunk/net/iucv/Makefile create mode 100644 trunk/net/iucv/af_iucv.c create mode 100644 trunk/net/iucv/iucv.c create mode 100644 trunk/net/netfilter/nf_conntrack_sane.c create mode 100644 trunk/net/netfilter/xt_TCPMSS.c create mode 100644 trunk/net/x25/x25_forward.c create mode 100644 trunk/sound/drivers/portman2x4.c create mode 100644 trunk/sound/i2c/other/pt2258.c create mode 100644 trunk/sound/isa/wavefront/yss225.c create mode 100644 trunk/sound/pci/hda/patch_conexant.c create mode 100644 trunk/sound/pci/hda/patch_via.c create mode 100644 trunk/sound/pci/ice1712/wtm.c create mode 100644 trunk/sound/pci/ice1712/wtm.h create mode 100644 trunk/sound/soc/Kconfig create mode 100644 trunk/sound/soc/Makefile create mode 100644 trunk/sound/soc/at91/Kconfig create mode 100644 trunk/sound/soc/at91/Makefile create mode 100644 trunk/sound/soc/at91/at91-i2s.c create mode 100644 trunk/sound/soc/at91/at91-i2s.h create mode 100644 trunk/sound/soc/at91/at91-pcm.c create mode 100644 trunk/sound/soc/at91/at91-pcm.h create mode 100644 trunk/sound/soc/at91/eti_b1_wm8731.c create mode 100644 trunk/sound/soc/codecs/Kconfig create mode 100644 trunk/sound/soc/codecs/Makefile create mode 100644 trunk/sound/soc/codecs/ac97.c create mode 100644 trunk/sound/soc/codecs/ac97.h create mode 100644 trunk/sound/soc/codecs/wm8731.c create mode 100644 trunk/sound/soc/codecs/wm8731.h create mode 100644 trunk/sound/soc/codecs/wm8750.c create mode 100644 trunk/sound/soc/codecs/wm8750.h create mode 100644 trunk/sound/soc/codecs/wm9712.c create mode 100644 trunk/sound/soc/codecs/wm9712.h create mode 100644 trunk/sound/soc/pxa/Kconfig create mode 100644 trunk/sound/soc/pxa/Makefile create mode 100644 trunk/sound/soc/pxa/corgi.c create mode 100644 trunk/sound/soc/pxa/poodle.c create mode 100644 trunk/sound/soc/pxa/pxa2xx-ac97.c create mode 100644 trunk/sound/soc/pxa/pxa2xx-ac97.h create mode 100644 trunk/sound/soc/pxa/pxa2xx-i2s.c create mode 100644 trunk/sound/soc/pxa/pxa2xx-i2s.h create mode 100644 trunk/sound/soc/pxa/pxa2xx-pcm.c create mode 100644 trunk/sound/soc/pxa/pxa2xx-pcm.h create mode 100644 trunk/sound/soc/pxa/spitz.c create mode 100644 trunk/sound/soc/pxa/tosa.c create mode 100644 trunk/sound/soc/soc-core.c create mode 100644 trunk/sound/soc/soc-dapm.c diff --git a/[refs] b/[refs] index 5452b22ca2ef..db6996c62048 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 0a9b0db19262dbb09f3a34195e68cafd5dc3fa10 +refs/heads/master: 2fd592e45b9c89d69e126f172d0f991e2af955e5 diff --git a/trunk/Documentation/crypto/api-intro.txt b/trunk/Documentation/crypto/api-intro.txt index 5a03a2801d67..e41a79aa71ce 100644 --- a/trunk/Documentation/crypto/api-intro.txt +++ b/trunk/Documentation/crypto/api-intro.txt @@ -193,6 +193,7 @@ Original developers of the crypto algorithms: Kartikey Mahendra Bhatt (CAST6) Jon Oberheide (ARC4) Jouni Malinen (Michael MIC) + NTT(Nippon Telegraph and Telephone Corporation) (Camellia) SHA1 algorithm contributors: Jean-Francois Dive @@ -246,6 +247,9 @@ Tiger algorithm contributors: VIA PadLock contributors: Michal Ludvig +Camellia algorithm contributors: + NTT(Nippon Telegraph and Telephone Corporation) (Camellia) + Generic scatterwalk code by Adam J. Richter Please send any credits updates or corrections to: diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index 2dc5e5da8f88..4a1d8979ed92 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -186,18 +186,6 @@ Who: Greg Kroah-Hartman --------------------------- -What: find_trylock_page -When: January 2007 -Why: The interface no longer has any callers left in the kernel. It - is an odd interface (compared with other find_*_page functions), in - that it does not take a refcount to the page, only the page lock. - It should be replaced with find_get_page or find_lock_page if possible. - This feature removal can be reevaluated if users of the interface - cannot cleanly use something else. -Who: Nick Piggin - ---------------------------- - What: Interrupt only SA_* flags When: Januar 2007 Why: The interrupt related SA_* flags are replaced by IRQF_* to move them diff --git a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt index 9fef210ab50a..c30ff1bb2d10 100644 --- a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt @@ -242,6 +242,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ac97_clock - AC'97 clock (default = 48000) ac97_quirk - AC'97 workaround for strange hardware See "AC97 Quirk Option" section below. + ac97_codec - Workaround to specify which AC'97 codec + instead of probing. If this works for you + file a bug with your `lspci -vn` output. + -2 -- Force probing. + -1 -- Default behavior. + 0-2 -- Use the specified codec. spdif_aclink - S/PDIF transfer over AC-link (default = 1) This module supports one card and autoprobe. @@ -779,6 +785,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. asus-dig ASUS with SPDIF out asus-dig2 ASUS with SPDIF out (using GPIO2) uniwill 3-jack + fujitsu Fujitsu Laptops (Pi1536) F1734 2-jack lg LG laptop (m1 express dual) lg-lw LG LW20/LW25 laptop @@ -800,14 +807,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ALC262 fujitsu Fujitsu Laptop hp-bpc HP xw4400/6400/8400/9400 laptops + hp-bpc-d7000 HP BPC D7000 benq Benq ED8 + hippo Hippo (ATI) with jack detection, Sony UX-90s + hippo_1 Hippo (Benq) with jack detection basic fixed pin assignment w/o SPDIF auto auto-config reading BIOS (default) ALC882/885 3stack-dig 3-jack with SPDIF I/O - 6stck-dig 6-jack digital with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O arima Arima W820Di1 + macpro MacPro support auto auto-config reading BIOS (default) ALC883/888 @@ -817,6 +828,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O 6stack-dig-demo 6-jack digital for Intel demo board acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) + medion Medion Laptops + targa-dig Targa/MSI + targa-2ch-dig Targs/MSI with 2-channel + laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) auto auto-config reading BIOS (default) ALC861/660 @@ -825,6 +840,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 6stack-dig 6-jack with SPDIF I/O 3stack-660 3-jack (for ALC660) uniwill-m31 Uniwill M31 laptop + toshiba Toshiba laptop support + asus Asus laptop support + asus-laptop ASUS F2/F3 laptops + auto auto-config reading BIOS (default) + + ALC861VD/660VD + 3stack 3-jack + 3stack-dig 3-jack with SPDIF OUT + 6stack-dig 6-jack with SPDIF OUT + 3stack-660 3-jack (for ALC660VD) auto auto-config reading BIOS (default) CMI9880 @@ -845,6 +870,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) + ultra 2-channel with EAPD (Samsung Ultra tablet PC) AD1988 6stack 6-jack @@ -854,12 +880,31 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. laptop 3-jack with hp-jack automute laptop-dig ditto with SPDIF auto auto-config reading BIOS (default) + + Conexant 5045 + laptop Laptop config + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + + Conexant 5047 + laptop Basic Laptop config + laptop-hp Laptop config for some HP models (subdevice 30A5) + laptop-eapd Laptop config with EAPD support + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y STAC9200/9205/9220/9221/9254 ref Reference board 3stack D945 3stack 5stack D945 5stack + SPDIF + STAC9202/9250/9251 + ref Reference board, base config + m2-2 Some Gateway MX series laptops + m6 Some Gateway NX series laptops + STAC9227/9228/9229/927x ref Reference board 3stack D965 3stack @@ -974,6 +1019,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards. * MidiMan M Audio Revolution 5.1 * MidiMan M Audio Revolution 7.1 + * MidiMan M Audio Audiophile 192 * AMP Ltd AUDIO2000 * TerraTec Aureon 5.1 Sky * TerraTec Aureon 7.1 Space @@ -993,7 +1039,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. model - Use the given board model, one of the following: revo51, revo71, amp2000, prodigy71, prodigy71lt, - prodigy192, aureon51, aureon71, universe, + prodigy192, aureon51, aureon71, universe, ap192, k8x800, phase22, phase28, ms300, av710 This module supports multiple cards and autoprobe. @@ -1049,6 +1095,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. buggy_semaphore - Enable workaround for hardwares with buggy semaphores (e.g. on some ASUS laptops) (default off) + spdif_aclink - Use S/PDIF over AC-link instead of direct connection + from the controller chip + (0 = off, 1 = on, -1 = default) This module supports one chip and autoprobe. @@ -1371,6 +1420,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple cards. + Module snd-portman2x4 + --------------------- + + Module for Midiman Portman 2x4 parallel port MIDI interface + + This module supports multiple cards. + Module snd-powermac (on ppc only) --------------------------------- diff --git a/trunk/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/trunk/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl index 1f3ae3e32d69..c4d2e3507af9 100644 --- a/trunk/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl +++ b/trunk/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl @@ -36,7 +36,7 @@ Management of Cards and Devices - Card Managment + Card Management !Esound/core/init.c Device Components @@ -59,7 +59,7 @@ PCM Format Helpers !Esound/core/pcm_misc.c - PCM Memory Managment + PCM Memory Management !Esound/core/pcm_memory.c diff --git a/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index ccd0a953953d..74d3a35b59bc 100644 --- a/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/trunk/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -1360,8 +1360,7 @@ substream->runtime. This runtime pointer holds the various information; it holds the copy of hw_params and sw_params configurations, the buffer - pointers, mmap records, spinlocks, etc. Almost everyhing you + pointers, mmap records, spinlocks, etc. Almost everything you need for controlling the PCM can be found there. @@ -2340,7 +2339,7 @@ struct _snd_pcm_runtime { When the PCM substreams can be synchronized (typically, - synchorinized start/stop of a playback and a capture streams), + synchronized start/stop of a playback and a capture streams), you can give SNDRV_PCM_INFO_SYNC_START, too. In this case, you'll need to check the linked-list of PCM substreams in the trigger callback. This will be @@ -3062,8 +3061,7 @@ struct _snd_pcm_runtime { Interrupt Handler Case #1 lock); @@ -3106,8 +3104,7 @@ struct _snd_pcm_runtime { Interrupt Handler Case #2 lock); @@ -3247,7 +3244,7 @@ struct _snd_pcm_runtime { You can even define your own constraint rules. For example, let's suppose my_chip can manage a substream of 1 channel if and only if the format is S16_LE, otherwise it supports any format - specified in the snd_pcm_hardware stucture (or in any + specified in the snd_pcm_hardware structure (or in any other constraint_list). You can build a rule like this: @@ -3690,16 +3687,6 @@ struct _snd_pcm_runtime { - - Here, the chip instance is retrieved via - snd_kcontrol_chip() macro. This macro - just accesses to kcontrol->private_data. The - kcontrol->private_data field is - given as the argument of snd_ctl_new() - (see the later subsection - Constructor). - - The value field is depending on the type of control as well as on info callback. For example, @@ -3780,7 +3767,7 @@ struct _snd_pcm_runtime { Like get callback, when the control has more than one elements, - all elemehts must be evaluated in this callback, too. + all elements must be evaluated in this callback, too. @@ -5541,12 +5528,12 @@ struct _snd_pcm_runtime { #ifdef CONFIG_PM static int snd_my_suspend(struct pci_dev *pci, pm_message_t state) { - .... /* do things for suspsend */ + .... /* do things for suspend */ return 0; } static int snd_my_resume(struct pci_dev *pci) { - .... /* do things for suspsend */ + .... /* do things for suspend */ return 0; } #endif @@ -6111,7 +6098,7 @@ struct _snd_pcm_runtime { - + Acknowledgments I would like to thank Phil Kerr for his help for improvement and diff --git a/trunk/Documentation/sound/alsa/hda_codec.txt b/trunk/Documentation/sound/alsa/hda_codec.txt index 0be57ed81302..4eaae2a45534 100644 --- a/trunk/Documentation/sound/alsa/hda_codec.txt +++ b/trunk/Documentation/sound/alsa/hda_codec.txt @@ -277,11 +277,11 @@ Helper Functions snd_hda_get_codec_name() stores the codec name on the given string. snd_hda_check_board_config() can be used to obtain the configuration -information matching with the device. Define the table with struct -hda_board_config entries (zero-terminated), and pass it to the -function. The function checks the modelname given as a module -parameter, and PCI subsystem IDs. If the matching entry is found, it -returns the config field value. +information matching with the device. Define the model string table +and the table with struct snd_pci_quirk entries (zero-terminated), +and pass it to the function. The function checks the modelname given +as a module parameter, and PCI subsystem IDs. If the matching entry +is found, it returns the config field value. snd_hda_add_new_ctls() can be used to create and add control entries. Pass the zero-terminated array of struct snd_kcontrol_new. The same array diff --git a/trunk/Documentation/sound/alsa/soc/DAI.txt b/trunk/Documentation/sound/alsa/soc/DAI.txt new file mode 100644 index 000000000000..58cbfd01ea8f --- /dev/null +++ b/trunk/Documentation/sound/alsa/soc/DAI.txt @@ -0,0 +1,56 @@ +ASoC currently supports the three main Digital Audio Interfaces (DAI) found on +SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM. + + +AC97 +==== + + AC97 is a five wire interface commonly found on many PC sound cards. It is +now also popular in many portable devices. This DAI has a reset line and time +multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines. +The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the +frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97 +frame is 21uS long and is divided into 13 time slots. + +The AC97 specification can be found at :- +http://www.intel.com/design/chipsets/audio/ac97_r23.pdf + + +I2S +=== + + I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and +Rx lines are used for audio transmision, whilst the bit clock (BCLK) and +left/right clock (LRC) synchronise the link. I2S is flexible in that either the +controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock +usually varies depending on the sample rate and the master system clock +(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate +ADC and DAC LRCLK's, this allows for similtanious capture and playback at +different sample rates. + +I2S has several different operating modes:- + + o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC + transition. + + o Left Justified - MSB is transmitted on transition of LRC. + + o Right Justified - MSB is transmitted sample size BCLK's before LRC + transition. + +PCM +=== + +PCM is another 4 wire interface, very similar to I2S, that can support a more +flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used +to synchronise the link whilst the Tx and Rx lines are used to transmit and +receive the audio data. Bit clock usually varies depending on sample rate +whilst sync runs at the sample rate. PCM also supports Time Division +Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This +is sometimes referred to as network mode). + +Common PCM operating modes:- + + o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC. + + o Mode B - MSB is transmitted on rising edge of FRAME/SYNC. diff --git a/trunk/Documentation/sound/alsa/soc/clocking.txt b/trunk/Documentation/sound/alsa/soc/clocking.txt new file mode 100644 index 000000000000..e93960d53a1e --- /dev/null +++ b/trunk/Documentation/sound/alsa/soc/clocking.txt @@ -0,0 +1,51 @@ +Audio Clocking +============== + +This text describes the audio clocking terms in ASoC and digital audio in +general. Note: Audio clocking can be complex ! + + +Master Clock +------------ + +Every audio subsystem is driven by a master clock (sometimes refered to as MCLK +or SYSCLK). This audio master clock can be derived from a number of sources +(e.g. crystal, PLL, CPU clock) and is responsible for producing the correct +audio playback and capture sample rates. + +Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that +their speed can be altered by software (depending on the system use and to save +power). Other master clocks are fixed at at set frequency (i.e. crystals). + + +DAI Clocks +---------- +The Digital Audio Interface is usually driven by a Bit Clock (often referred to +as BCLK). This clock is used to drive the digital audio data across the link +between the codec and CPU. + +The DAI also has a frame clock to signal the start of each audio frame. This +clock is sometimes referred to as LRC (left right clock) or FRAME. This clock +runs at exactly the sample rate (LRC = Rate). + +Bit Clock can be generated as follows:- + +BCLK = MCLK / x + + or + +BCLK = LRC * x + + or + +BCLK = LRC * Channels * Word Size + +This relationship depends on the codec or SoC CPU in particular. In general +it's best to configure BCLK to the lowest possible speed (depending on your +rate, number of channels and wordsize) to save on power. + +It's also desireable to use the codec (if possible) to drive (or master) the +audio clocks as it's usually gives more accurate sample rates than the CPU. + + + diff --git a/trunk/Documentation/sound/alsa/soc/codec.txt b/trunk/Documentation/sound/alsa/soc/codec.txt new file mode 100644 index 000000000000..48983c75aad9 --- /dev/null +++ b/trunk/Documentation/sound/alsa/soc/codec.txt @@ -0,0 +1,197 @@ +ASoC Codec Driver +================= + +The codec driver is generic and hardware independent code that configures the +codec to provide audio capture and playback. It should contain no code that is +specific to the target platform or machine. All platform and machine specific +code should be added to the platform and machine drivers respectively. + +Each codec driver *must* provide the following features:- + + 1) Codec DAI and PCM configuration + 2) Codec control IO - using I2C, 3 Wire(SPI) or both API's + 3) Mixers and audio controls + 4) Codec audio operations + +Optionally, codec drivers can also provide:- + + 5) DAPM description. + 6) DAPM event handler. + 7) DAC Digital mute control. + +It's probably best to use this guide in conjuction with the existing codec +driver code in sound/soc/codecs/ + +ASoC Codec driver breakdown +=========================== + +1 - Codec DAI and PCM configuration +----------------------------------- +Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and +PCM's capablities and operations. This struct is exported so that it can be +registered with the core by your machine driver. + +e.g. + +struct snd_soc_codec_dai wm8731_dai = { + .name = "WM8731", + /* playback capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + /* capture capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + /* pcm operations - see section 4 below */ + .ops = { + .prepare = wm8731_pcm_prepare, + .hw_params = wm8731_hw_params, + .shutdown = wm8731_shutdown, + }, + /* DAI operations - see DAI.txt */ + .dai_ops = { + .digital_mute = wm8731_mute, + .set_sysclk = wm8731_set_dai_sysclk, + .set_fmt = wm8731_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(wm8731_dai); + + +2 - Codec control IO +-------------------- +The codec can ususally be controlled via an I2C or SPI style interface (AC97 +combines control with data in the DAI). The codec drivers will have to provide +functions to read and write the codec registers along with supplying a register +cache:- + + /* IO control data and register cache */ + void *control_data; /* codec control (i2c/3wire) data */ + void *reg_cache; + +Codec read/write should do any data formatting and call the hardware read write +below to perform the IO. These functions are called by the core and alsa when +performing DAPM or changing the mixer:- + + unsigned int (*read)(struct snd_soc_codec *, unsigned int); + int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); + +Codec hardware IO functions - usually points to either the I2C, SPI or AC97 +read/write:- + + hw_write_t hw_write; + hw_read_t hw_read; + + +3 - Mixers and audio controls +----------------------------- +All the codec mixers and audio controls can be defined using the convenience +macros defined in soc.h. + + #define SOC_SINGLE(xname, reg, shift, mask, invert) + +Defines a single control as follows:- + + xname = Control name e.g. "Playback Volume" + reg = codec register + shift = control bit(s) offset in register + mask = control bit size(s) e.g. mask of 7 = 3 bits + invert = the control is inverted + +Other macros include:- + + #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) + +A stereo control + + #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) + +A stereo control spanning 2 registers + + #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) + +Defines an single enumerated control as follows:- + + xreg = register + xshift = control bit(s) offset in register + xmask = control bit(s) size + xtexts = pointer to array of strings that describe each setting + + #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) + +Defines a stereo enumerated control + + +4 - Codec Audio Operations +-------------------------- +The codec driver also supports the following alsa operations:- + +/* SoC audio ops */ +struct snd_soc_ops { + int (*startup)(struct snd_pcm_substream *); + void (*shutdown)(struct snd_pcm_substream *); + int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); + int (*hw_free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); +}; + +Please refer to the alsa driver PCM documentation for details. +http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm + + +5 - DAPM description. +--------------------- +The Dynamic Audio Power Management description describes the codec's power +components, their relationships and registers to the ASoC core. Please read +dapm.txt for details of building the description. + +Please also see the examples in other codec drivers. + + +6 - DAPM event handler +---------------------- +This function is a callback that handles codec domain PM calls and system +domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep +when not in use. + +Power states:- + + SNDRV_CTL_POWER_D0: /* full On */ + /* vref/mid, clk and osc on, active */ + + SNDRV_CTL_POWER_D1: /* partial On */ + SNDRV_CTL_POWER_D2: /* partial On */ + + SNDRV_CTL_POWER_D3hot: /* Off, with power */ + /* everything off except vref/vmid, inactive */ + + SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */ + + +7 - Codec DAC digital mute control. +------------------------------------ +Most codecs have a digital mute before the DAC's that can be used to minimise +any system noise. The mute stops any digital data from entering the DAC. + +A callback can be created that is called by the core for each codec DAI when the +mute is applied or freed. + +i.e. + +static int wm8974_mute(struct snd_soc_codec *codec, + struct snd_soc_codec_dai *dai, int mute) +{ + u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf; + if(mute) + wm8974_write(codec, WM8974_DAC, mute_reg | 0x40); + else + wm8974_write(codec, WM8974_DAC, mute_reg); + return 0; +} diff --git a/trunk/Documentation/sound/alsa/soc/dapm.txt b/trunk/Documentation/sound/alsa/soc/dapm.txt new file mode 100644 index 000000000000..c11877f5b4a1 --- /dev/null +++ b/trunk/Documentation/sound/alsa/soc/dapm.txt @@ -0,0 +1,297 @@ +Dynamic Audio Power Management for Portable Devices +=================================================== + +1. Description +============== + +Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices +to use the minimum amount of power within the audio subsystem at all times. It +is independent of other kernel PM and as such, can easily co-exist with the +other PM systems. + +DAPM is also completely transparent to all user space applications as all power +switching is done within the ASoC core. No code changes or recompiling are +required for user space applications. DAPM makes power switching descisions based +upon any audio stream (capture/playback) activity and audio mixer settings +within the device. + +DAPM spans the whole machine. It covers power control within the entire audio +subsystem, this includes internal codec power blocks and machine level power +systems. + +There are 4 power domains within DAPM + + 1. Codec domain - VREF, VMID (core codec and audio power) + Usually controlled at codec probe/remove and suspend/resume, although + can be set at stream time if power is not needed for sidetone, etc. + + 2. Platform/Machine domain - physically connected inputs and outputs + Is platform/machine and user action specific, is configured by the + machine driver and responds to asynchronous events e.g when HP + are inserted + + 3. Path domain - audio susbsystem signal paths + Automatically set when mixer and mux settings are changed by the user. + e.g. alsamixer, amixer. + + 4. Stream domain - DAC's and ADC's. + Enabled and disabled when stream playback/capture is started and + stopped respectively. e.g. aplay, arecord. + +All DAPM power switching descisons are made automatically by consulting an audio +routing map of the whole machine. This map is specific to each machine and +consists of the interconnections between every audio component (including +internal codec components). All audio components that effect power are called +widgets hereafter. + + +2. DAPM Widgets +=============== + +Audio DAPM widgets fall into a number of types:- + + o Mixer - Mixes several analog signals into a single analog signal. + o Mux - An analog switch that outputs only 1 of it's inputs. + o PGA - A programmable gain amplifier or attenuation widget. + o ADC - Analog to Digital Converter + o DAC - Digital to Analog Converter + o Switch - An analog switch + o Input - A codec input pin + o Output - A codec output pin + o Headphone - Headphone (and optional Jack) + o Mic - Mic (and optional Jack) + o Line - Line Input/Output (and optional Jack) + o Speaker - Speaker + o Pre - Special PRE widget (exec before all others) + o Post - Special POST widget (exec after all others) + +(Widgets are defined in include/sound/soc-dapm.h) + +Widgets are usually added in the codec driver and the machine driver. There are +convience macros defined in soc-dapm.h that can be used to quickly build a +list of widgets of the codecs and machines DAPM widgets. + +Most widgets have a name, register, shift and invert. Some widgets have extra +parameters for stream name and kcontrols. + + +2.1 Stream Domain Widgets +------------------------- + +Stream Widgets relate to the stream power domain and only consist of ADC's +(analog to digital converters) and DAC's (digital to analog converters). + +Stream widgets have the following format:- + +SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert), + +NOTE: the stream name must match the corresponding stream name in your codecs +snd_soc_codec_dai. + +e.g. stream widgets for HiFi playback and capture + +SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1), +SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1), + + +2.2 Path Domain Widgets +----------------------- + +Path domain widgets have a ability to control or effect the audio signal or +audio paths within the audio subsystem. They have the following form:- + +SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls) + +Any widget kcontrols can be set using the controls and num_controls members. + +e.g. Mixer widget (the kcontrols are declared first) + +/* Output Mixer */ +static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), +SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), +SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), +}; + +SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls, + ARRAY_SIZE(wm8731_output_mixer_controls)), + + +2.3 Platform/Machine domain Widgets +----------------------------------- + +Machine widgets are different from codec widgets in that they don't have a +codec register bit associated with them. A machine widget is assigned to each +machine audio component (non codec) that can be independently powered. e.g. + + o Speaker Amp + o Microphone Bias + o Jack connectors + +A machine widget can have an optional call back. + +e.g. Jack connector widget for an external Mic that enables Mic Bias +when the Mic is inserted:- + +static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event) +{ + if(SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); + else + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); + + return 0; +} + +SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), + + +2.4 Codec Domain +---------------- + +The Codec power domain has no widgets and is handled by the codecs DAPM event +handler. This handler is called when the codec powerstate is changed wrt to any +stream event or by kernel PM events. + + +2.5 Virtual Widgets +------------------- + +Sometimes widgets exist in the codec or machine audio map that don't have any +corresponding register bit for power control. In this case it's necessary to +create a virtual widget - a widget with no control bits e.g. + +SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0), + +This can be used to merge to signal paths together in software. + +After all the widgets have been defined, they can then be added to the DAPM +subsystem individually with a call to snd_soc_dapm_new_control(). + + +3. Codec Widget Interconnections +================================ + +Widgets are connected to each other within the codec and machine by audio +paths (called interconnections). Each interconnection must be defined in order +to create a map of all audio paths between widgets. +This is easiest with a diagram of the codec (and schematic of the machine audio +system), as it requires joining widgets together via their audio signal paths. + +i.e. from the WM8731 codec's output mixer (wm8731.c) + +The WM8731 output mixer has 3 inputs (sources) + + 1. Line Bypass Input + 2. DAC (HiFi playback) + 3. Mic Sidetone Input + +Each input in this example has a kcontrol associated with it (defined in example +above) and is connected to the output mixer via it's kcontrol name. We can now +connect the destination widget (wrt audio signal) with it's source widgets. + + /* output mixer */ + {"Output Mixer", "Line Bypass Switch", "Line Input"}, + {"Output Mixer", "HiFi Playback Switch", "DAC"}, + {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, + +So we have :- + + Destination Widget <=== Path Name <=== Source Widget + +Or:- + + Sink, Path, Source + +Or :- + + "Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch". + +When there is no path name connecting widgets (e.g. a direct connection) we +pass NULL for the path name. + +Interconnections are created with a call to:- + +snd_soc_dapm_connect_input(codec, sink, path, source); + +Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and +interconnections have been registered with the core. This causes the core to +scan the codec and machine so that the internal DAPM state matches the +physical state of the machine. + + +3.1 Machine Widget Interconnections +----------------------------------- +Machine widget interconnections are created in the same way as codec ones and +directly connect the codec pins to machine level widgets. + +e.g. connects the speaker out codec pins to the internal speaker. + + /* ext speaker connected to codec pins LOUT2, ROUT2 */ + {"Ext Spk", NULL , "ROUT2"}, + {"Ext Spk", NULL , "LOUT2"}, + +This allows the DAPM to power on and off pins that are connected (and in use) +and pins that are NC respectively. + + +4 Endpoint Widgets +=================== +An endpoint is a start or end point (widget) of an audio signal within the +machine and includes the codec. e.g. + + o Headphone Jack + o Internal Speaker + o Internal Mic + o Mic Jack + o Codec Pins + +When a codec pin is NC it can be marked as not used with a call to + +snd_soc_dapm_set_endpoint(codec, "Widget Name", 0); + +The last argument is 0 for inactive and 1 for active. This way the pin and its +input widget will never be powered up and consume power. + +This also applies to machine widgets. e.g. if a headphone is connected to a +jack then the jack can be marked active. If the headphone is removed, then +the headphone jack can be marked inactive. + + +5 DAPM Widget Events +==================== + +Some widgets can register their interest with the DAPM core in PM events. +e.g. A Speaker with an amplifier registers a widget so the amplifier can be +powered only when the spk is in use. + +/* turn speaker amplifier on/off depending on use */ +static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + + return 0; +} + +/* corgi machine dapm widgets */ +static const struct snd_soc_dapm_widget wm8731_dapm_widgets = + SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event); + +Please see soc-dapm.h for all other widgets that support events. + + +5.1 Event types +--------------- + +The following event types are supported by event widgets. + +/* dapm event types */ +#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */ +#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */ +#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */ +#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */ +#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */ +#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */ diff --git a/trunk/Documentation/sound/alsa/soc/machine.txt b/trunk/Documentation/sound/alsa/soc/machine.txt new file mode 100644 index 000000000000..72bd222f2a21 --- /dev/null +++ b/trunk/Documentation/sound/alsa/soc/machine.txt @@ -0,0 +1,113 @@ +ASoC Machine Driver +=================== + +The ASoC machine (or board) driver is the code that glues together the platform +and codec drivers. + +The machine driver can contain codec and platform specific code. It registers +the audio subsystem with the kernel as a platform device and is represented by +the following struct:- + +/* SoC machine */ +struct snd_soc_machine { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + + /* the pre and post PM functions are used to do any PM work before and + * after the codec and DAI's do any PM work. */ + int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); + int (*suspend_post)(struct platform_device *pdev, pm_message_t state); + int (*resume_pre)(struct platform_device *pdev); + int (*resume_post)(struct platform_device *pdev); + + /* machine stream operations */ + struct snd_soc_ops *ops; + + /* CPU <--> Codec DAI links */ + struct snd_soc_dai_link *dai_link; + int num_links; +}; + +probe()/remove() +---------------- +probe/remove are optional. Do any machine specific probe here. + + +suspend()/resume() +------------------ +The machine driver has pre and post versions of suspend and resume to take care +of any machine audio tasks that have to be done before or after the codec, DAI's +and DMA is suspended and resumed. Optional. + + +Machine operations +------------------ +The machine specific audio operations can be set here. Again this is optional. + + +Machine DAI Configuration +------------------------- +The machine DAI configuration glues all the codec and CPU DAI's together. It can +also be used to set up the DAI system clock and for any machine related DAI +initialisation e.g. the machine audio map can be connected to the codec audio +map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c +for examples. + +struct snd_soc_dai_link is used to set up each DAI in your machine. e.g. + +/* corgi digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link corgi_dai = { + .name = "WM8731", + .stream_name = "WM8731", + .cpu_dai = &pxa_i2s_dai, + .codec_dai = &wm8731_dai, + .init = corgi_wm8731_init, + .ops = &corgi_ops, +}; + +struct snd_soc_machine then sets up the machine with it's DAI's. e.g. + +/* corgi audio machine driver */ +static struct snd_soc_machine snd_soc_machine_corgi = { + .name = "Corgi", + .dai_link = &corgi_dai, + .num_links = 1, +}; + + +Machine Audio Subsystem +----------------------- + +The machine soc device glues the platform, machine and codec driver together. +Private data can also be set here. e.g. + +/* corgi audio private data */ +static struct wm8731_setup_data corgi_wm8731_setup = { + .i2c_address = 0x1b, +}; + +/* corgi audio subsystem */ +static struct snd_soc_device corgi_snd_devdata = { + .machine = &snd_soc_machine_corgi, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm8731, + .codec_data = &corgi_wm8731_setup, +}; + + +Machine Power Map +----------------- + +The machine driver can optionally extend the codec power map and to become an +audio power map of the audio subsystem. This allows for automatic power up/down +of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack +sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for +details. + + +Machine Controls +---------------- + +Machine specific audio mixer controls can be added in the dai init function. \ No newline at end of file diff --git a/trunk/Documentation/sound/alsa/soc/overview.txt b/trunk/Documentation/sound/alsa/soc/overview.txt new file mode 100644 index 000000000000..753c5cc5984a --- /dev/null +++ b/trunk/Documentation/sound/alsa/soc/overview.txt @@ -0,0 +1,83 @@ +ALSA SoC Layer +============== + +The overall project goal of the ALSA System on Chip (ASoC) layer is to provide +better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00, +iMX, etc) and portable audio codecs. Currently there is some support in the +kernel for SoC audio, however it has some limitations:- + + * Currently, codec drivers are often tightly coupled to the underlying SoC + cpu. This is not ideal and leads to code duplication i.e. Linux now has 4 + different wm8731 drivers for 4 different SoC platforms. + + * There is no standard method to signal user initiated audio events. + e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion + event. These are quite common events on portable devices and ofter require + machine specific code to re route audio, enable amps etc after such an event. + + * Current drivers tend to power up the entire codec when playing + (or recording) audio. This is fine for a PC, but tends to waste a lot of + power on portable devices. There is also no support for saving power via + changing codec oversampling rates, bias currents, etc. + + +ASoC Design +=========== + +The ASoC layer is designed to address these issues and provide the following +features :- + + * Codec independence. Allows reuse of codec drivers on other platforms + and machines. + + * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface + and codec registers it's audio interface capabilities with the core and are + subsequently matched and configured when the application hw params are known. + + * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to + it's minimum power state at all times. This includes powering up/down + internal power blocks depending on the internal codec audio routing and any + active streams. + + * Pop and click reduction. Pops and clicks can be reduced by powering the + codec up/down in the correct sequence (including using digital mute). ASoC + signals the codec when to change power states. + + * Machine specific controls: Allow machines to add controls to the sound card + e.g. volume control for speaker amp. + +To achieve all this, ASoC basically splits an embedded audio system into 3 +components :- + + * Codec driver: The codec driver is platform independent and contains audio + controls, audio interface capabilities, codec dapm definition and codec IO + functions. + + * Platform driver: The platform driver contains the audio dma engine and audio + interface drivers (e.g. I2S, AC97, PCM) for that platform. + + * Machine driver: The machine driver handles any machine specific controls and + audio events. i.e. turing on an amp at start of playback. + + +Documentation +============= + +The documentation is spilt into the following sections:- + +overview.txt: This file. + +codec.txt: Codec driver internals. + +DAI.txt: Description of Digital Audio Interface standards and how to configure +a DAI within your codec and CPU DAI drivers. + +dapm.txt: Dynamic Audio Power Management + +platform.txt: Platform audio DMA and DAI. + +machine.txt: Machine driver internals. + +pop_clicks.txt: How to minimise audio artifacts. + +clocking.txt: ASoC clocking for best power performance. \ No newline at end of file diff --git a/trunk/Documentation/sound/alsa/soc/platform.txt b/trunk/Documentation/sound/alsa/soc/platform.txt new file mode 100644 index 000000000000..e95b16d5a53b --- /dev/null +++ b/trunk/Documentation/sound/alsa/soc/platform.txt @@ -0,0 +1,58 @@ +ASoC Platform Driver +==================== + +An ASoC platform driver can be divided into audio DMA and SoC DAI configuration +and control. The platform drivers only target the SoC CPU and must have no board +specific code. + +Audio DMA +========= + +The platform DMA driver optionally supports the following alsa operations:- + +/* SoC audio ops */ +struct snd_soc_ops { + int (*startup)(struct snd_pcm_substream *); + void (*shutdown)(struct snd_pcm_substream *); + int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); + int (*hw_free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); + int (*trigger)(struct snd_pcm_substream *, int); +}; + +The platform driver exports it's DMA functionailty via struct snd_soc_platform:- + +struct snd_soc_platform { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); + int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); + + /* pcm creation and destruction */ + int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *); + void (*pcm_free)(struct snd_pcm *); + + /* platform stream ops */ + struct snd_pcm_ops *pcm_ops; +}; + +Please refer to the alsa driver documentation for details of audio DMA. +http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm + +An example DMA driver is soc/pxa/pxa2xx-pcm.c + + +SoC DAI Drivers +=============== + +Each SoC DAI driver must provide the following features:- + + 1) Digital audio interface (DAI) description + 2) Digital audio interface configuration + 3) PCM's description + 4) Sysclk configuration + 5) Suspend and resume (optional) + +Please see codec.txt for a description of items 1 - 4. diff --git a/trunk/Documentation/sound/alsa/soc/pops_clicks.txt b/trunk/Documentation/sound/alsa/soc/pops_clicks.txt new file mode 100644 index 000000000000..2cf7ee5b3d74 --- /dev/null +++ b/trunk/Documentation/sound/alsa/soc/pops_clicks.txt @@ -0,0 +1,52 @@ +Audio Pops and Clicks +===================== + +Pops and clicks are unwanted audio artifacts caused by the powering up and down +of components within the audio subsystem. This is noticable on PC's when an +audio module is either loaded or unloaded (at module load time the sound card is +powered up and causes a popping noise on the speakers). + +Pops and clicks can be more frequent on portable systems with DAPM. This is +because the components within the subsystem are being dynamically powered +depending on the audio usage and this can subsequently cause a small pop or +click every time a component power state is changed. + + +Minimising Playback Pops and Clicks +=================================== + +Playback pops in portable audio subsystems cannot be completely eliminated atm, +however future audio codec hardware will have better pop and click supression. +Pops can be reduced within playback by powering the audio components in a +specific order. This order is different for startup and shutdown and follows +some basic rules:- + + Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute + + Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC + +This assumes that the codec PCM output path from the DAC is via a mixer and then +a PGA (programmable gain amplifier) before being output to the speakers. + + +Minimising Capture Pops and Clicks +================================== + +Capture artifacts are somewhat easier to get rid as we can delay activating the +ADC until all the pops have occured. This follows similar power rules to +playback in that components are powered in a sequence depending upon stream +startup or shutdown. + + Startup Order - Input PGA --> Mixers --> ADC + + Shutdown Order - ADC --> Mixers --> Input PGA + + +Zipper Noise +============ +An unwanted zipper noise can occur within the audio playback or capture stream +when a volume control is changed near its maximum gain value. The zipper noise +is heard when the gain increase or decrease changes the mean audio signal +amplitude too quickly. It can be minimised by enabling the zero cross setting +for each volume control. The ZC forces the gain change to occur when the signal +crosses the zero amplitude line. diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index fe35f3ac4cd3..a6c1ebd18d0f 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -1114,7 +1114,7 @@ S: Supported DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER P: Tobias Ringstrom M: tori@unhappy.mine.nu -L: linux-kernel@vger.kernel.org +L: netdev@vger.kernel.org S: Maintained DOCBOOK FOR DOCUMENTATION @@ -2361,7 +2361,7 @@ S: Maintained NETWORKING [WIRELESS] P: John W. Linville M: linville@tuxdriver.com -L: netdev@vger.kernel.org +L: linux-wireless@vger.kernel.org T: git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.git S: Maintained @@ -3037,6 +3037,12 @@ M: perex@suse.cz L: alsa-devel@alsa-project.org S: Maintained +SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT +P: Liam Girdwood +M: liam.girdwood@wolfsonmicro.com +L: alsa-devel@alsa-project.org +S: Supported + SPI SUBSYSTEM P: David Brownell M: dbrownell@users.sourceforge.net @@ -3287,6 +3293,11 @@ L: vtun@office.satix.net W: http://vtun.sourceforge.net/tun S: Maintained +TURBOCHANNEL SUBSYSTEM +P: Maciej W. Rozycki +M: macro@linux-mips.org +S: Maintained + U14-34F SCSI DRIVER P: Dario Ballabio M: ballabio_dario@emc.com diff --git a/trunk/arch/avr32/boards/atstk1000/Makefile b/trunk/arch/avr32/boards/atstk1000/Makefile index df9499480530..8e0992201bb9 100644 --- a/trunk/arch/avr32/boards/atstk1000/Makefile +++ b/trunk/arch/avr32/boards/atstk1000/Makefile @@ -1,2 +1,2 @@ -obj-y += setup.o spi.o flash.o +obj-y += setup.o flash.o obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o diff --git a/trunk/arch/avr32/boards/atstk1000/atstk1002.c b/trunk/arch/avr32/boards/atstk1000/atstk1002.c index 32b361f31c2c..d47e39f0e971 100644 --- a/trunk/arch/avr32/boards/atstk1000/atstk1002.c +++ b/trunk/arch/avr32/boards/atstk1000/atstk1002.c @@ -8,17 +8,24 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include #include #include #include +#include #include #include +#include #include #include +#include + + +#define SW2_DEFAULT /* MMCI and UART_A available */ struct eth_addr { u8 addr[6]; @@ -29,6 +36,16 @@ static struct eth_addr __initdata hw_addr[2]; static struct eth_platform_data __initdata eth_data[2]; extern struct lcdc_platform_data atstk1000_fb0_data; +static struct spi_board_info spi_board_info[] __initdata = { + { + .modalias = "ltv350qv", + .controller_data = (void *)GPIO_PIN_PA(4), + .max_speed_hz = 16000000, + .bus_num = 0, + .chip_select = 1, + }, +}; + /* * The next two functions should go away as the boot loader is * supposed to initialize the macb address registers with a valid @@ -86,23 +103,53 @@ static void __init set_hw_addr(struct platform_device *pdev) void __init setup_board(void) { - at32_map_usart(1, 0); /* /dev/ttyS0 */ - at32_map_usart(2, 1); /* /dev/ttyS1 */ - at32_map_usart(3, 2); /* /dev/ttyS2 */ +#ifdef SW2_DEFAULT + at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */ +#else + at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */ +#endif + /* USART 2/unused: expansion connector */ + at32_map_usart(3, 2); /* USART 3/C: /dev/ttyS2, DB9 */ at32_setup_serial_console(0); } static int __init atstk1002_init(void) { + /* + * ATSTK1000 uses 32-bit SDRAM interface. Reserve the + * SDRAM-specific pins so that nobody messes with them. + */ + at32_reserve_pin(GPIO_PIN_PE(0)); /* DATA[16] */ + at32_reserve_pin(GPIO_PIN_PE(1)); /* DATA[17] */ + at32_reserve_pin(GPIO_PIN_PE(2)); /* DATA[18] */ + at32_reserve_pin(GPIO_PIN_PE(3)); /* DATA[19] */ + at32_reserve_pin(GPIO_PIN_PE(4)); /* DATA[20] */ + at32_reserve_pin(GPIO_PIN_PE(5)); /* DATA[21] */ + at32_reserve_pin(GPIO_PIN_PE(6)); /* DATA[22] */ + at32_reserve_pin(GPIO_PIN_PE(7)); /* DATA[23] */ + at32_reserve_pin(GPIO_PIN_PE(8)); /* DATA[24] */ + at32_reserve_pin(GPIO_PIN_PE(9)); /* DATA[25] */ + at32_reserve_pin(GPIO_PIN_PE(10)); /* DATA[26] */ + at32_reserve_pin(GPIO_PIN_PE(11)); /* DATA[27] */ + at32_reserve_pin(GPIO_PIN_PE(12)); /* DATA[28] */ + at32_reserve_pin(GPIO_PIN_PE(13)); /* DATA[29] */ + at32_reserve_pin(GPIO_PIN_PE(14)); /* DATA[30] */ + at32_reserve_pin(GPIO_PIN_PE(15)); /* DATA[31] */ + at32_reserve_pin(GPIO_PIN_PE(26)); /* SDCS */ + at32_add_system_devices(); +#ifdef SW2_DEFAULT at32_add_device_usart(0); +#else at32_add_device_usart(1); +#endif at32_add_device_usart(2); set_hw_addr(at32_add_device_eth(0, ð_data[0])); + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); at32_add_device_spi(0); at32_add_device_lcdc(0, &atstk1000_fb0_data); diff --git a/trunk/arch/avr32/boards/atstk1000/spi.c b/trunk/arch/avr32/boards/atstk1000/spi.c deleted file mode 100644 index 567726c82c6e..000000000000 --- a/trunk/arch/avr32/boards/atstk1000/spi.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * ATSTK1000 SPI devices - * - * Copyright (C) 2005 Atmel Norway - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include - -static struct spi_board_info spi_board_info[] __initdata = { - { - .modalias = "ltv350qv", - .max_speed_hz = 16000000, - .bus_num = 0, - .chip_select = 1, - }, -}; - -static int board_init_spi(void) -{ - spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); - return 0; -} -arch_initcall(board_init_spi); diff --git a/trunk/arch/avr32/kernel/cpu.c b/trunk/arch/avr32/kernel/cpu.c index 342452ba2049..2e72fd2699df 100644 --- a/trunk/arch/avr32/kernel/cpu.c +++ b/trunk/arch/avr32/kernel/cpu.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/avr32/kernel/irq.c b/trunk/arch/avr32/kernel/irq.c index 856f3548e664..fd311248c143 100644 --- a/trunk/arch/avr32/kernel/irq.c +++ b/trunk/arch/avr32/kernel/irq.c @@ -57,6 +57,7 @@ int show_interrupts(struct seq_file *p, void *v) seq_printf(p, "%3d: ", i); for_each_online_cpu(cpu) seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); + seq_printf(p, " %8s", irq_desc[i].chip->name ? : "-"); seq_printf(p, " %s", action->name); for (action = action->next; action; action = action->next) seq_printf(p, ", %s", action->name); diff --git a/trunk/arch/avr32/kernel/setup.c b/trunk/arch/avr32/kernel/setup.c index a34211601008..c6734aefb559 100644 --- a/trunk/arch/avr32/kernel/setup.c +++ b/trunk/arch/avr32/kernel/setup.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -174,8 +175,7 @@ static int __init parse_tag_mem_range(struct tag *tag, * Copy the data so the bootmem init code doesn't need to care * about it. */ - if (mem_range_next_free >= - (sizeof(mem_range_cache) / sizeof(mem_range_cache[0]))) + if (mem_range_next_free >= ARRAY_SIZE(mem_range_cache)) panic("Physical memory map too complex!\n"); new = &mem_range_cache[mem_range_next_free++]; diff --git a/trunk/arch/avr32/lib/libgcc.h b/trunk/arch/avr32/lib/libgcc.h deleted file mode 100644 index 5a091b5e3618..000000000000 --- a/trunk/arch/avr32/lib/libgcc.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Definitions for various functions 'borrowed' from gcc-3.4.3 */ - -#define BITS_PER_UNIT 8 - -typedef int QItype __attribute__ ((mode (QI))); -typedef unsigned int UQItype __attribute__ ((mode (QI))); -typedef int HItype __attribute__ ((mode (HI))); -typedef unsigned int UHItype __attribute__ ((mode (HI))); -typedef int SItype __attribute__ ((mode (SI))); -typedef unsigned int USItype __attribute__ ((mode (SI))); -typedef int DItype __attribute__ ((mode (DI))); -typedef unsigned int UDItype __attribute__ ((mode (DI))); -typedef float SFtype __attribute__ ((mode (SF))); -typedef float DFtype __attribute__ ((mode (DF))); -typedef int word_type __attribute__ ((mode (__word__))); - -#define W_TYPE_SIZE (4 * BITS_PER_UNIT) -#define Wtype SItype -#define UWtype USItype -#define HWtype SItype -#define UHWtype USItype -#define DWtype DItype -#define UDWtype UDItype -#define __NW(a,b) __ ## a ## si ## b -#define __NDW(a,b) __ ## a ## di ## b - -struct DWstruct {Wtype high, low;}; - -typedef union -{ - struct DWstruct s; - DWtype ll; -} DWunion; diff --git a/trunk/arch/avr32/lib/longlong.h b/trunk/arch/avr32/lib/longlong.h deleted file mode 100644 index cd5e369ac437..000000000000 --- a/trunk/arch/avr32/lib/longlong.h +++ /dev/null @@ -1,98 +0,0 @@ -/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. - Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000 - Free Software Foundation, Inc. - - This definition file is free software; you can redistribute it - and/or modify it under the terms of the GNU General Public - License as published by the Free Software Foundation; either - version 2, or (at your option) any later version. - - This definition file 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. */ - -/* Borrowed from gcc-3.4.3 */ - -#define __BITS4 (W_TYPE_SIZE / 4) -#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) -#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) -#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) - -#define count_leading_zeros(count, x) ((count) = __builtin_clz(x)) - -#define __udiv_qrnnd_c(q, r, n1, n0, d) \ - do { \ - UWtype __d1, __d0, __q1, __q0; \ - UWtype __r1, __r0, __m; \ - __d1 = __ll_highpart (d); \ - __d0 = __ll_lowpart (d); \ - \ - __r1 = (n1) % __d1; \ - __q1 = (n1) / __d1; \ - __m = (UWtype) __q1 * __d0; \ - __r1 = __r1 * __ll_B | __ll_highpart (n0); \ - if (__r1 < __m) \ - { \ - __q1--, __r1 += (d); \ - if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ - if (__r1 < __m) \ - __q1--, __r1 += (d); \ - } \ - __r1 -= __m; \ - \ - __r0 = __r1 % __d1; \ - __q0 = __r1 / __d1; \ - __m = (UWtype) __q0 * __d0; \ - __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ - if (__r0 < __m) \ - { \ - __q0--, __r0 += (d); \ - if (__r0 >= (d)) \ - if (__r0 < __m) \ - __q0--, __r0 += (d); \ - } \ - __r0 -= __m; \ - \ - (q) = (UWtype) __q1 * __ll_B | __q0; \ - (r) = __r0; \ - } while (0) - -#define udiv_qrnnd __udiv_qrnnd_c - -#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - do { \ - UWtype __x; \ - __x = (al) - (bl); \ - (sh) = (ah) - (bh) - (__x > (al)); \ - (sl) = __x; \ - } while (0) - -#define umul_ppmm(w1, w0, u, v) \ - do { \ - UWtype __x0, __x1, __x2, __x3; \ - UHWtype __ul, __vl, __uh, __vh; \ - \ - __ul = __ll_lowpart (u); \ - __uh = __ll_highpart (u); \ - __vl = __ll_lowpart (v); \ - __vh = __ll_highpart (v); \ - \ - __x0 = (UWtype) __ul * __vl; \ - __x1 = (UWtype) __ul * __vh; \ - __x2 = (UWtype) __uh * __vl; \ - __x3 = (UWtype) __uh * __vh; \ - \ - __x1 += __ll_highpart (__x0);/* this can't give carry */ \ - __x1 += __x2; /* but this indeed can */ \ - if (__x1 < __x2) /* did we get it? */ \ - __x3 += __ll_B; /* yes, add it in the proper pos. */ \ - \ - (w1) = __x3 + __ll_highpart (__x1); \ - (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ - } while (0) diff --git a/trunk/arch/avr32/mach-at32ap/Makefile b/trunk/arch/avr32/mach-at32ap/Makefile index f62eb6915510..b21bea9af8b1 100644 --- a/trunk/arch/avr32/mach-at32ap/Makefile +++ b/trunk/arch/avr32/mach-at32ap/Makefile @@ -1,2 +1,2 @@ -obj-y += at32ap.o clock.o pio.o intc.o extint.o hsmc.o +obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o diff --git a/trunk/arch/avr32/mach-at32ap/at32ap7000.c b/trunk/arch/avr32/mach-at32ap/at32ap7000.c index 48f4ef38c70e..c1e477ec7576 100644 --- a/trunk/arch/avr32/mach-at32ap/at32ap7000.c +++ b/trunk/arch/avr32/mach-at32ap/at32ap7000.c @@ -496,9 +496,16 @@ static struct resource pio3_resource[] = { DEFINE_DEV(pio, 3); DEV_CLK(mck, pio3, pba, 13); +static struct resource pio4_resource[] = { + PBMEM(0xffe03800), + IRQ(17), +}; +DEFINE_DEV(pio, 4); +DEV_CLK(mck, pio4, pba, 14); + void __init at32_add_system_devices(void) { - system_manager.eim_first_irq = NR_INTERNAL_IRQS; + system_manager.eim_first_irq = EIM_IRQ_BASE; platform_device_register(&at32_sm_device); platform_device_register(&at32_intc0_device); @@ -509,6 +516,7 @@ void __init at32_add_system_devices(void) platform_device_register(&pio1_device); platform_device_register(&pio2_device); platform_device_register(&pio3_device); + platform_device_register(&pio4_device); } /* -------------------------------------------------------------------- @@ -521,7 +529,7 @@ static struct atmel_uart_data atmel_usart0_data = { }; static struct resource atmel_usart0_resource[] = { PBMEM(0xffe00c00), - IRQ(7), + IRQ(6), }; DEFINE_DEV_DATA(atmel_usart, 0); DEV_CLK(usart, atmel_usart0, pba, 4); @@ -583,7 +591,7 @@ static inline void configure_usart3_pins(void) select_peripheral(PB(17), PERIPH_B, 0); /* TXD */ } -static struct platform_device *at32_usarts[4]; +static struct platform_device *__initdata at32_usarts[4]; void __init at32_map_usart(unsigned int hw_id, unsigned int line) { @@ -728,12 +736,19 @@ at32_add_device_eth(unsigned int id, struct eth_platform_data *data) /* -------------------------------------------------------------------- * SPI * -------------------------------------------------------------------- */ -static struct resource spi0_resource[] = { +static struct resource atmel_spi0_resource[] = { PBMEM(0xffe00000), IRQ(3), }; -DEFINE_DEV(spi, 0); -DEV_CLK(mck, spi0, pba, 0); +DEFINE_DEV(atmel_spi, 0); +DEV_CLK(spi_clk, atmel_spi0, pba, 0); + +static struct resource atmel_spi1_resource[] = { + PBMEM(0xffe00400), + IRQ(4), +}; +DEFINE_DEV(atmel_spi, 1); +DEV_CLK(spi_clk, atmel_spi1, pba, 1); struct platform_device *__init at32_add_device_spi(unsigned int id) { @@ -741,13 +756,33 @@ struct platform_device *__init at32_add_device_spi(unsigned int id) switch (id) { case 0: - pdev = &spi0_device; + pdev = &atmel_spi0_device; select_peripheral(PA(0), PERIPH_A, 0); /* MISO */ select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */ select_peripheral(PA(2), PERIPH_A, 0); /* SCK */ - select_peripheral(PA(3), PERIPH_A, 0); /* NPCS0 */ - select_peripheral(PA(4), PERIPH_A, 0); /* NPCS1 */ - select_peripheral(PA(5), PERIPH_A, 0); /* NPCS2 */ + + /* NPCS[2:0] */ + at32_select_gpio(GPIO_PIN_PA(3), + AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + at32_select_gpio(GPIO_PIN_PA(4), + AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + at32_select_gpio(GPIO_PIN_PA(5), + AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + break; + + case 1: + pdev = &atmel_spi1_device; + select_peripheral(PB(0), PERIPH_B, 0); /* MISO */ + select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */ + select_peripheral(PB(5), PERIPH_B, 0); /* SCK */ + + /* NPCS[2:0] */ + at32_select_gpio(GPIO_PIN_PB(2), + AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + at32_select_gpio(GPIO_PIN_PB(3), + AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + at32_select_gpio(GPIO_PIN_PB(4), + AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); break; default: @@ -860,6 +895,7 @@ struct clk *at32_clock_list[] = { &pio1_mck, &pio2_mck, &pio3_mck, + &pio4_mck, &atmel_usart0_usart, &atmel_usart1_usart, &atmel_usart2_usart, @@ -868,7 +904,8 @@ struct clk *at32_clock_list[] = { &macb0_pclk, &macb1_hclk, &macb1_pclk, - &spi0_mck, + &atmel_spi0_spi_clk, + &atmel_spi1_spi_clk, &lcdc0_hclk, &lcdc0_pixclk, }; @@ -880,6 +917,7 @@ void __init at32_portmux_init(void) at32_init_pio(&pio1_device); at32_init_pio(&pio2_device); at32_init_pio(&pio3_device); + at32_init_pio(&pio4_device); } void __init at32_clock_init(void) diff --git a/trunk/arch/avr32/mach-at32ap/extint.c b/trunk/arch/avr32/mach-at32ap/extint.c index b59272e81b9a..4a60eccfebd2 100644 --- a/trunk/arch/avr32/mach-at32ap/extint.c +++ b/trunk/arch/avr32/mach-at32ap/extint.c @@ -55,20 +55,11 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type) unsigned long flags; int ret = 0; + flow_type &= IRQ_TYPE_SENSE_MASK; if (flow_type == IRQ_TYPE_NONE) flow_type = IRQ_TYPE_LEVEL_LOW; desc = &irq_desc[irq]; - desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); - desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; - - if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { - desc->status |= IRQ_LEVEL; - set_irq_handler(irq, handle_level_irq); - } else { - set_irq_handler(irq, handle_edge_irq); - } - spin_lock_irqsave(&sm->lock, flags); mode = sm_readl(sm, EIM_MODE); @@ -97,9 +88,16 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type) break; } - sm_writel(sm, EIM_MODE, mode); - sm_writel(sm, EIM_EDGE, edge); - sm_writel(sm, EIM_LEVEL, level); + if (ret == 0) { + sm_writel(sm, EIM_MODE, mode); + sm_writel(sm, EIM_EDGE, edge); + sm_writel(sm, EIM_LEVEL, level); + + if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + flow_type |= IRQ_LEVEL; + desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); + desc->status |= flow_type; + } spin_unlock_irqrestore(&sm->lock, flags); @@ -122,8 +120,6 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc) unsigned long status, pending; unsigned int i, ext_irq; - spin_lock(&sm->lock); - status = sm_readl(sm, EIM_ISR); pending = status & sm_readl(sm, EIM_IMR); @@ -133,10 +129,11 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc) ext_irq = i + sm->eim_first_irq; ext_desc = irq_desc + ext_irq; - ext_desc->handle_irq(ext_irq, ext_desc); + if (ext_desc->status & IRQ_LEVEL) + handle_level_irq(ext_irq, ext_desc); + else + handle_edge_irq(ext_irq, ext_desc); } - - spin_unlock(&sm->lock); } static int __init eim_init(void) @@ -168,8 +165,9 @@ static int __init eim_init(void) sm->eim_chip = &eim_chip; for (i = 0; i < nr_irqs; i++) { + /* NOTE the handler we set here is ignored by the demux */ set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip, - handle_edge_irq); + handle_level_irq); set_irq_chip_data(sm->eim_first_irq + i, sm); } diff --git a/trunk/arch/avr32/mach-at32ap/pio.c b/trunk/arch/avr32/mach-at32ap/pio.c index f1280ed8ed6d..9ba5654cde11 100644 --- a/trunk/arch/avr32/mach-at32ap/pio.c +++ b/trunk/arch/avr32/mach-at32ap/pio.c @@ -12,7 +12,9 @@ #include #include #include +#include +#include #include #include @@ -26,7 +28,8 @@ struct pio_device { const struct platform_device *pdev; struct clk *clk; u32 pinmux_mask; - char name[32]; + u32 gpio_mask; + char name[8]; }; static struct pio_device pio_dev[MAX_NR_PIO_DEVICES]; @@ -76,6 +79,9 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph, if (!(flags & AT32_GPIOF_PULLUP)) pio_writel(pio, PUDR, mask); + /* gpio_request NOT allowed */ + set_bit(pin_index, &pio->gpio_mask); + return; fail: @@ -99,19 +105,52 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags) goto fail; } - pio_writel(pio, PUER, mask); - if (flags & AT32_GPIOF_HIGH) - pio_writel(pio, SODR, mask); - else - pio_writel(pio, CODR, mask); - if (flags & AT32_GPIOF_OUTPUT) + if (flags & AT32_GPIOF_OUTPUT) { + if (flags & AT32_GPIOF_HIGH) + pio_writel(pio, SODR, mask); + else + pio_writel(pio, CODR, mask); + pio_writel(pio, PUDR, mask); pio_writel(pio, OER, mask); - else + } else { + if (flags & AT32_GPIOF_PULLUP) + pio_writel(pio, PUER, mask); + else + pio_writel(pio, PUDR, mask); + if (flags & AT32_GPIOF_DEGLITCH) + pio_writel(pio, IFER, mask); + else + pio_writel(pio, IFDR, mask); pio_writel(pio, ODR, mask); + } pio_writel(pio, PER, mask); - if (!(flags & AT32_GPIOF_PULLUP)) - pio_writel(pio, PUDR, mask); + + /* gpio_request now allowed */ + clear_bit(pin_index, &pio->gpio_mask); + + return; + +fail: + dump_stack(); +} + +/* Reserve a pin, preventing anyone else from changing its configuration. */ +void __init at32_reserve_pin(unsigned int pin) +{ + struct pio_device *pio; + unsigned int pin_index = pin & 0x1f; + + pio = gpio_to_pio(pin); + if (unlikely(!pio)) { + printk("pio: invalid pin %u\n", pin); + goto fail; + } + + if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) { + printk("%s: pin %u is busy\n", pio->name, pin_index); + goto fail; + } return; @@ -119,20 +158,197 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags) dump_stack(); } +/*--------------------------------------------------------------------------*/ + +/* GPIO API */ + +int gpio_request(unsigned int gpio, const char *label) +{ + struct pio_device *pio; + unsigned int pin; + + pio = gpio_to_pio(gpio); + if (!pio) + return -ENODEV; + + pin = gpio & 0x1f; + if (test_and_set_bit(pin, &pio->gpio_mask)) + return -EBUSY; + + return 0; +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned int gpio) +{ + struct pio_device *pio; + unsigned int pin; + + pio = gpio_to_pio(gpio); + if (!pio) { + printk(KERN_ERR + "gpio: attempted to free invalid pin %u\n", gpio); + return; + } + + pin = gpio & 0x1f; + if (!test_and_clear_bit(pin, &pio->gpio_mask)) + printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n", + pio->name, pin); +} +EXPORT_SYMBOL(gpio_free); + +int gpio_direction_input(unsigned int gpio) +{ + struct pio_device *pio; + unsigned int pin; + + pio = gpio_to_pio(gpio); + if (!pio) + return -ENODEV; + + pin = gpio & 0x1f; + pio_writel(pio, ODR, 1 << pin); + + return 0; +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned int gpio) +{ + struct pio_device *pio; + unsigned int pin; + + pio = gpio_to_pio(gpio); + if (!pio) + return -ENODEV; + + pin = gpio & 0x1f; + pio_writel(pio, OER, 1 << pin); + + return 0; +} +EXPORT_SYMBOL(gpio_direction_output); + +int gpio_get_value(unsigned int gpio) +{ + struct pio_device *pio = &pio_dev[gpio >> 5]; + + return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1; +} +EXPORT_SYMBOL(gpio_get_value); + +void gpio_set_value(unsigned int gpio, int value) +{ + struct pio_device *pio = &pio_dev[gpio >> 5]; + u32 mask; + + mask = 1 << (gpio & 0x1f); + if (value) + pio_writel(pio, SODR, mask); + else + pio_writel(pio, CODR, mask); +} +EXPORT_SYMBOL(gpio_set_value); + +/*--------------------------------------------------------------------------*/ + +/* GPIO IRQ support */ + +static void gpio_irq_mask(unsigned irq) +{ + unsigned gpio = irq_to_gpio(irq); + struct pio_device *pio = &pio_dev[gpio >> 5]; + + pio_writel(pio, IDR, 1 << (gpio & 0x1f)); +} + +static void gpio_irq_unmask(unsigned irq) +{ + unsigned gpio = irq_to_gpio(irq); + struct pio_device *pio = &pio_dev[gpio >> 5]; + + pio_writel(pio, IER, 1 << (gpio & 0x1f)); +} + +static int gpio_irq_type(unsigned irq, unsigned type) +{ + if (type != IRQ_TYPE_EDGE_BOTH && type != IRQ_TYPE_NONE) + return -EINVAL; + + return 0; +} + +static struct irq_chip gpio_irqchip = { + .name = "gpio", + .mask = gpio_irq_mask, + .unmask = gpio_irq_unmask, + .set_type = gpio_irq_type, +}; + +static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct pio_device *pio = get_irq_chip_data(irq); + unsigned gpio_irq; + + gpio_irq = (unsigned) get_irq_data(irq); + for (;;) { + u32 isr; + struct irq_desc *d; + + /* ack pending GPIO interrupts */ + isr = pio_readl(pio, ISR) & pio_readl(pio, IMR); + if (!isr) + break; + do { + int i; + + i = ffs(isr) - 1; + isr &= ~(1 << i); + + i += gpio_irq; + d = &irq_desc[i]; + + d->handle_irq(i, d); + } while (isr); + } +} + +static void __init +gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq) +{ + unsigned i; + + set_irq_chip_data(irq, pio); + set_irq_data(irq, (void *) gpio_irq); + + for (i = 0; i < 32; i++, gpio_irq++) { + set_irq_chip_data(gpio_irq, pio); + set_irq_chip_and_handler(gpio_irq, &gpio_irqchip, + handle_simple_irq); + } + + set_irq_chained_handler(irq, gpio_irq_handler); +} + +/*--------------------------------------------------------------------------*/ + static int __init pio_probe(struct platform_device *pdev) { struct pio_device *pio = NULL; + int irq = platform_get_irq(pdev, 0); + int gpio_irq_base = GPIO_IRQ_BASE + pdev->id * 32; BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES); pio = &pio_dev[pdev->id]; BUG_ON(!pio->regs); - /* TODO: Interrupts */ + gpio_irq_setup(pio, irq, gpio_irq_base); platform_set_drvdata(pdev, pio); - printk(KERN_INFO "%s: Atmel Port Multiplexer at 0x%p (irq %d)\n", - pio->name, pio->regs, platform_get_irq(pdev, 0)); + printk(KERN_DEBUG "%s: base 0x%p, irq %d chains %d..%d\n", + pio->name, pio->regs, irq, gpio_irq_base, gpio_irq_base + 31); return 0; } @@ -148,7 +364,7 @@ static int __init pio_init(void) { return platform_driver_register(&pio_driver); } -subsys_initcall(pio_init); +postcore_initcall(pio_init); void __init at32_init_pio(struct platform_device *pdev) { @@ -184,6 +400,13 @@ void __init at32_init_pio(struct platform_device *pdev) pio->pdev = pdev; pio->regs = ioremap(regs->start, regs->end - regs->start + 1); - pio_writel(pio, ODR, ~0UL); - pio_writel(pio, PER, ~0UL); + /* + * request_gpio() is only valid for pins that have been + * explicitly configured as GPIO and not previously requested + */ + pio->gpio_mask = ~0UL; + + /* start with irqs disabled and acked */ + pio_writel(pio, IDR, ~0UL); + (void) pio_readl(pio, ISR); } diff --git a/trunk/arch/avr32/mm/cache.c b/trunk/arch/avr32/mm/cache.c index 450515b245a0..fb13f72e9a02 100644 --- a/trunk/arch/avr32/mm/cache.c +++ b/trunk/arch/avr32/mm/cache.c @@ -22,18 +22,34 @@ void invalidate_dcache_region(void *start, size_t size) { - unsigned long v, begin, end, linesz; + unsigned long v, begin, end, linesz, mask; + int flush = 0; linesz = boot_cpu_data.dcache.linesz; + mask = linesz - 1; + + /* when first and/or last cachelines are shared, flush them + * instead of invalidating ... never discard valid data! + */ + begin = (unsigned long)start; + end = begin + size - 1; + + if (begin & mask) { + flush_dcache_line(start); + begin += linesz; + flush = 1; + } + if ((end & mask) != mask) { + flush_dcache_line((void *)end); + end -= linesz; + flush = 1; + } - //printk("invalidate dcache: %p + %u\n", start, size); - - /* You asked for it, you got it */ - begin = (unsigned long)start & ~(linesz - 1); - end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); - - for (v = begin; v < end; v += linesz) + /* remaining cachelines only need invalidation */ + for (v = begin; v <= end; v += linesz) invalidate_dcache_line((void *)v); + if (flush) + flush_write_buffer(); } void clean_dcache_region(void *start, size_t size) diff --git a/trunk/arch/i386/kernel/hpet.c b/trunk/arch/i386/kernel/hpet.c index 45a8685bb60b..0b29d41322a2 100644 --- a/trunk/arch/i386/kernel/hpet.c +++ b/trunk/arch/i386/kernel/hpet.c @@ -12,7 +12,7 @@ /* FSEC = 10^-15 NSEC = 10^-9 */ #define FSEC_PER_NSEC 1000000 -static void *hpet_ptr; +static void __iomem *hpet_ptr; static cycle_t read_hpet(void) { @@ -40,8 +40,7 @@ static int __init init_hpet_clocksource(void) return -ENODEV; /* calculate the hpet address: */ - hpet_base = - (void __iomem*)ioremap_nocache(hpet_address, HPET_MMAP_SIZE); + hpet_base = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); hpet_ptr = hpet_base + HPET_COUNTER; /* calculate the frequency: */ diff --git a/trunk/arch/i386/kernel/io_apic.c b/trunk/arch/i386/kernel/io_apic.c index 5592fa6e1fa1..ba8d302a0b72 100644 --- a/trunk/arch/i386/kernel/io_apic.c +++ b/trunk/arch/i386/kernel/io_apic.c @@ -126,7 +126,7 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i */ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) { - volatile struct io_apic *io_apic = io_apic_base(apic); + volatile struct io_apic __iomem *io_apic = io_apic_base(apic); if (sis_apic_bug) writel(reg, &io_apic->index); writel(value, &io_apic->data); diff --git a/trunk/arch/i386/kernel/sysenter.c b/trunk/arch/i386/kernel/sysenter.c index 5da744204d10..bc882a2b1db6 100644 --- a/trunk/arch/i386/kernel/sysenter.c +++ b/trunk/arch/i386/kernel/sysenter.c @@ -70,11 +70,12 @@ void enable_sep_cpu(void) */ extern const char vsyscall_int80_start, vsyscall_int80_end; extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; -static void *syscall_page; +static struct page *syscall_pages[1]; int __init sysenter_setup(void) { - syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + syscall_pages[0] = virt_to_page(syscall_page); #ifdef CONFIG_COMPAT_VDSO __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY); @@ -96,31 +97,12 @@ int __init sysenter_setup(void) } #ifndef CONFIG_COMPAT_VDSO -static struct page *syscall_nopage(struct vm_area_struct *vma, - unsigned long adr, int *type) -{ - struct page *p = virt_to_page(adr - vma->vm_start + syscall_page); - get_page(p); - return p; -} - -/* Prevent VMA merging */ -static void syscall_vma_close(struct vm_area_struct *vma) -{ -} - -static struct vm_operations_struct syscall_vm_ops = { - .close = syscall_vma_close, - .nopage = syscall_nopage, -}; - /* Defined in vsyscall-sysenter.S */ extern void SYSENTER_RETURN; /* Setup a VMA at program startup for the vsyscall page */ int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) { - struct vm_area_struct *vma; struct mm_struct *mm = current->mm; unsigned long addr; int ret; @@ -132,38 +114,25 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) goto up_fail; } - vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (!vma) { - ret = -ENOMEM; - goto up_fail; - } - - vma->vm_start = addr; - vma->vm_end = addr + PAGE_SIZE; - /* MAYWRITE to allow gdb to COW and set breakpoints */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; /* + * MAYWRITE to allow gdb to COW and set breakpoints + * * Make sure the vDSO gets into every core dump. * Dumping its contents makes post-mortem fully interpretable later * without matching up the same kernel and hardware config to see * what PC values meant. */ - vma->vm_flags |= VM_ALWAYSDUMP; - vma->vm_flags |= mm->def_flags; - vma->vm_page_prot = protection_map[vma->vm_flags & 7]; - vma->vm_ops = &syscall_vm_ops; - vma->vm_mm = mm; - - ret = insert_vm_struct(mm, vma); - if (unlikely(ret)) { - kmem_cache_free(vm_area_cachep, vma); + ret = install_special_mapping(mm, addr, PAGE_SIZE, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + syscall_pages); + if (ret) goto up_fail; - } current->mm->context.vdso = (void *)addr; current_thread_info()->sysenter_return = (void *)VDSO_SYM(&SYSENTER_RETURN); - mm->total_vm++; up_fail: up_write(&mm->mmap_sem); return ret; diff --git a/trunk/arch/i386/mm/pageattr.c b/trunk/arch/i386/mm/pageattr.c index ad91528bdc14..e223b1d4981c 100644 --- a/trunk/arch/i386/mm/pageattr.c +++ b/trunk/arch/i386/mm/pageattr.c @@ -224,7 +224,7 @@ void global_flush_tlb(void) list_replace_init(&df_list, &l); spin_unlock_irq(&cpa_lock); if (!cpu_has_clflush) - flush_map(0); + flush_map(NULL); list_for_each_entry_safe(pg, next, &l, lru) { if (cpu_has_clflush) flush_map(page_address(pg)); diff --git a/trunk/arch/ia64/kernel/crash.c b/trunk/arch/ia64/kernel/crash.c index 9d92097ce96d..37bb16f07fc3 100644 --- a/trunk/arch/ia64/kernel/crash.c +++ b/trunk/arch/ia64/kernel/crash.c @@ -52,7 +52,7 @@ extern void ia64_dump_cpu_regs(void *); static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus); void -crash_save_this_cpu() +crash_save_this_cpu(void) { void *buf; unsigned long cfm, sof, sol; diff --git a/trunk/arch/ia64/kernel/smp.c b/trunk/arch/ia64/kernel/smp.c index f4c7f7769cf7..55ddd809b02d 100644 --- a/trunk/arch/ia64/kernel/smp.c +++ b/trunk/arch/ia64/kernel/smp.c @@ -221,13 +221,13 @@ send_IPI_self (int op) #ifdef CONFIG_KEXEC void -kdump_smp_send_stop() +kdump_smp_send_stop(void) { send_IPI_allbutself(IPI_KDUMP_CPU_STOP); } void -kdump_smp_send_init() +kdump_smp_send_init(void) { unsigned int cpu, self_cpu; self_cpu = smp_processor_id(); diff --git a/trunk/arch/mips/dec/Makefile b/trunk/arch/mips/dec/Makefile index ed181fdc3ac9..8b790c2900d5 100644 --- a/trunk/arch/mips/dec/Makefile +++ b/trunk/arch/mips/dec/Makefile @@ -6,6 +6,7 @@ obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \ kn02-irq.o kn02xa-berr.o reset.o setup.o time.o obj-$(CONFIG_PROM_CONSOLE) += promcon.o +obj-$(CONFIG_TC) += tc.o obj-$(CONFIG_CPU_HAS_WB) += wbflush.o EXTRA_AFLAGS := $(CFLAGS) diff --git a/trunk/arch/mips/dec/prom/identify.c b/trunk/arch/mips/dec/prom/identify.c index 81d5e878ddce..c4e3c1ea0d48 100644 --- a/trunk/arch/mips/dec/prom/identify.c +++ b/trunk/arch/mips/dec/prom/identify.c @@ -88,6 +88,7 @@ static inline void prom_init_kn02(void) { dec_kn_slot_base = KN02_SLOT_BASE; dec_kn_slot_size = KN02_SLOT_SIZE; + dec_tc_bus = 1; dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC); } @@ -96,6 +97,7 @@ static inline void prom_init_kn02xa(void) { dec_kn_slot_base = KN02XA_SLOT_BASE; dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); @@ -105,6 +107,7 @@ static inline void prom_init_kn03(void) { dec_kn_slot_base = KN03_SLOT_BASE; dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); diff --git a/trunk/arch/mips/dec/setup.c b/trunk/arch/mips/dec/setup.c index 1058e2f409bb..b8a5e75ba0ab 100644 --- a/trunk/arch/mips/dec/setup.c +++ b/trunk/arch/mips/dec/setup.c @@ -53,6 +53,8 @@ unsigned long dec_kn_slot_base, dec_kn_slot_size; EXPORT_SYMBOL(dec_kn_slot_base); EXPORT_SYMBOL(dec_kn_slot_size); +int dec_tc_bus; + spinlock_t ioasic_ssr_lock; volatile u32 *ioasic_base; diff --git a/trunk/arch/mips/dec/tc.c b/trunk/arch/mips/dec/tc.c new file mode 100644 index 000000000000..732027c79834 --- /dev/null +++ b/trunk/arch/mips/dec/tc.c @@ -0,0 +1,95 @@ +/* + * TURBOchannel architecture calls. + * + * Copyright (c) Harald Koerfgen, 1998 + * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons + * + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* + * Protected read byte from TURBOchannel slot space. + */ +int tc_preadb(u8 *valp, void __iomem *addr) +{ + return get_dbe(*valp, (u8 *)addr); +} + +/* + * Get TURBOchannel bus information as specified by the spec, plus + * the slot space base address and the number of slots. + */ +int __init tc_bus_get_info(struct tc_bus *tbus) +{ + if (!dec_tc_bus) + return -ENXIO; + + memcpy(&tbus->info, rex_gettcinfo(), sizeof(tbus->info)); + tbus->slot_base = CPHYSADDR((long)rex_slot_address(0)); + + switch (mips_machtype) { + case MACH_DS5000_200: + tbus->num_tcslots = 7; + break; + case MACH_DS5000_2X0: + case MACH_DS5900: + tbus->ext_slot_base = 0x20000000; + tbus->ext_slot_size = 0x20000000; + /* fall through */ + case MACH_DS5000_1XX: + tbus->num_tcslots = 3; + break; + case MACH_DS5000_XX: + tbus->num_tcslots = 2; + default: + break; + } + return 0; +} + +/* + * Get the IRQ for the specified slot. + */ +void __init tc_device_get_irq(struct tc_dev *tdev) +{ + switch (tdev->slot) { + case 0: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC0]; + break; + case 1: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC1]; + break; + case 2: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC2]; + break; + /* + * Yuck! DS5000/200 onboard devices + */ + case 5: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC5]; + break; + case 6: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC6]; + break; + default: + tdev->interrupt = -1; + break; + } +} diff --git a/trunk/arch/powerpc/kernel/vdso.c b/trunk/arch/powerpc/kernel/vdso.c index ae0ede19879d..50149ec6efa4 100644 --- a/trunk/arch/powerpc/kernel/vdso.c +++ b/trunk/arch/powerpc/kernel/vdso.c @@ -49,9 +49,13 @@ /* Max supported size for symbol names */ #define MAX_SYMNAME 64 +#define VDSO32_MAXPAGES (((0x3000 + PAGE_MASK) >> PAGE_SHIFT) + 2) +#define VDSO64_MAXPAGES (((0x3000 + PAGE_MASK) >> PAGE_SHIFT) + 2) + extern char vdso32_start, vdso32_end; static void *vdso32_kbase = &vdso32_start; unsigned int vdso32_pages; +static struct page *vdso32_pagelist[VDSO32_MAXPAGES]; unsigned long vdso32_sigtramp; unsigned long vdso32_rt_sigtramp; @@ -59,6 +63,7 @@ unsigned long vdso32_rt_sigtramp; extern char vdso64_start, vdso64_end; static void *vdso64_kbase = &vdso64_start; unsigned int vdso64_pages; +static struct page *vdso64_pagelist[VDSO64_MAXPAGES]; unsigned long vdso64_rt_sigtramp; #endif /* CONFIG_PPC64 */ @@ -164,55 +169,6 @@ static void dump_vdso_pages(struct vm_area_struct * vma) } #endif /* DEBUG */ -/* - * Keep a dummy vma_close for now, it will prevent VMA merging. - */ -static void vdso_vma_close(struct vm_area_struct * vma) -{ -} - -/* - * Our nopage() function, maps in the actual vDSO kernel pages, they will - * be mapped read-only by do_no_page(), and eventually COW'ed, either - * right away for an initial write access, or by do_wp_page(). - */ -static struct page * vdso_vma_nopage(struct vm_area_struct * vma, - unsigned long address, int *type) -{ - unsigned long offset = address - vma->vm_start; - struct page *pg; -#ifdef CONFIG_PPC64 - void *vbase = (vma->vm_mm->task_size > TASK_SIZE_USER32) ? - vdso64_kbase : vdso32_kbase; -#else - void *vbase = vdso32_kbase; -#endif - - DBG("vdso_vma_nopage(current: %s, address: %016lx, off: %lx)\n", - current->comm, address, offset); - - if (address < vma->vm_start || address > vma->vm_end) - return NOPAGE_SIGBUS; - - /* - * Last page is systemcfg. - */ - if ((vma->vm_end - address) <= PAGE_SIZE) - pg = virt_to_page(vdso_data); - else - pg = virt_to_page(vbase + offset); - - get_page(pg); - DBG(" ->page count: %d\n", page_count(pg)); - - return pg; -} - -static struct vm_operations_struct vdso_vmops = { - .close = vdso_vma_close, - .nopage = vdso_vma_nopage, -}; - /* * This is called from binfmt_elf, we create the special vma for the * vDSO and insert it into the mm struct tree @@ -221,20 +177,23 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; + struct page **vdso_pagelist; unsigned long vdso_pages; unsigned long vdso_base; int rc; #ifdef CONFIG_PPC64 if (test_thread_flag(TIF_32BIT)) { + vdso_pagelist = vdso32_pagelist; vdso_pages = vdso32_pages; vdso_base = VDSO32_MBASE; } else { + vdso_pagelist = vdso64_pagelist; vdso_pages = vdso64_pages; vdso_base = VDSO64_MBASE; } #else + vdso_pagelist = vdso32_pagelist; vdso_pages = vdso32_pages; vdso_base = VDSO32_MBASE; #endif @@ -262,17 +221,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, goto fail_mmapsem; } - - /* Allocate a VMA structure and fill it up */ - vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (vma == NULL) { - rc = -ENOMEM; - goto fail_mmapsem; - } - vma->vm_mm = mm; - vma->vm_start = vdso_base; - vma->vm_end = vma->vm_start + (vdso_pages << PAGE_SHIFT); - /* * our vma flags don't have VM_WRITE so by default, the process isn't * allowed to write those pages. @@ -282,32 +230,26 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, * and your nice userland gettimeofday will be totally dead. * It's fine to use that for setting breakpoints in the vDSO code * pages though - */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC; - /* + * * Make sure the vDSO gets into every core dump. * Dumping its contents makes post-mortem fully interpretable later * without matching up the same kernel and hardware config to see * what PC values meant. */ - vma->vm_flags |= VM_ALWAYSDUMP; - vma->vm_flags |= mm->def_flags; - vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; - vma->vm_ops = &vdso_vmops; - - /* Insert new VMA */ - rc = insert_vm_struct(mm, vma); + rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + vdso_pagelist); if (rc) - goto fail_vma; + goto fail_mmapsem; - /* Put vDSO base into mm struct and account for memory usage */ + /* Put vDSO base into mm struct */ current->mm->context.vdso_base = vdso_base; - mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + up_write(&mm->mmap_sem); return 0; - fail_vma: - kmem_cache_free(vm_area_cachep, vma); fail_mmapsem: up_write(&mm->mmap_sem); return rc; @@ -778,18 +720,26 @@ void __init vdso_init(void) } /* Make sure pages are in the correct state */ + BUG_ON(vdso32_pages + 2 > VDSO32_MAXPAGES); for (i = 0; i < vdso32_pages; i++) { struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE); ClearPageReserved(pg); get_page(pg); - + vdso32_pagelist[i] = pg; } + vdso32_pagelist[i++] = virt_to_page(vdso_data); + vdso32_pagelist[i] = NULL; + #ifdef CONFIG_PPC64 + BUG_ON(vdso64_pages + 2 > VDSO64_MAXPAGES); for (i = 0; i < vdso64_pages; i++) { struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE); ClearPageReserved(pg); get_page(pg); + vdso64_pagelist[i] = pg; } + vdso64_pagelist[i++] = virt_to_page(vdso_data); + vdso64_pagelist[i] = NULL; #endif /* CONFIG_PPC64 */ get_page(virt_to_page(vdso_data)); diff --git a/trunk/arch/powerpc/platforms/cell/iommu.c b/trunk/arch/powerpc/platforms/cell/iommu.c index b43466ba8096..67d617b60a23 100644 --- a/trunk/arch/powerpc/platforms/cell/iommu.c +++ b/trunk/arch/powerpc/platforms/cell/iommu.c @@ -149,7 +149,8 @@ static int cbe_nr_iommus; static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte, long n_ptes) { - unsigned long *reg, val; + unsigned long __iomem *reg; + unsigned long val; long n; reg = iommu->xlate_regs + IOC_IOPT_CacheInvd; @@ -592,7 +593,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off /* Init base fields */ i = cbe_nr_iommus++; iommu = &iommus[i]; - iommu->stab = 0; + iommu->stab = NULL; iommu->nid = nid; snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i); INIT_LIST_HEAD(&iommu->windows); diff --git a/trunk/arch/powerpc/platforms/celleb/pci.c b/trunk/arch/powerpc/platforms/celleb/pci.c index 867f83a7d0c9..98de836dfed3 100644 --- a/trunk/arch/powerpc/platforms/celleb/pci.c +++ b/trunk/arch/powerpc/platforms/celleb/pci.c @@ -65,13 +65,13 @@ static inline u8 celleb_fake_config_readb(void *addr) static inline u16 celleb_fake_config_readw(void *addr) { - u16 *p = addr; + __le16 *p = addr; return le16_to_cpu(*p); } static inline u32 celleb_fake_config_readl(void *addr) { - u32 *p = addr; + __le32 *p = addr; return le32_to_cpu(*p); } @@ -83,16 +83,16 @@ static inline void celleb_fake_config_writeb(u32 val, void *addr) static inline void celleb_fake_config_writew(u32 val, void *addr) { - u16 val16; - u16 *p = addr; + __le16 val16; + __le16 *p = addr; val16 = cpu_to_le16(val); *p = val16; } static inline void celleb_fake_config_writel(u32 val, void *addr) { - u32 val32; - u32 *p = addr; + __le32 val32; + __le32 *p = addr; val32 = cpu_to_le32(val); *p = val32; } diff --git a/trunk/arch/powerpc/platforms/celleb/scc_epci.c b/trunk/arch/powerpc/platforms/celleb/scc_epci.c index 0edbc0c4f338..c11b39c3776a 100644 --- a/trunk/arch/powerpc/platforms/celleb/scc_epci.c +++ b/trunk/arch/powerpc/platforms/celleb/scc_epci.c @@ -47,7 +47,7 @@ #if 0 /* test code for epci dummy read */ static void celleb_epci_dummy_read(struct pci_dev *dev) { - void *epci_base; + void __iomem *epci_base; struct device_node *node; struct pci_controller *hose; u32 val; @@ -58,7 +58,7 @@ static void celleb_epci_dummy_read(struct pci_dev *dev) if (!hose) return; - epci_base = (void *)hose->cfg_addr; + epci_base = hose->cfg_addr; val = in_be32(epci_base + SCC_EPCI_WATRP); iosync(); @@ -71,18 +71,18 @@ static inline void clear_and_disable_master_abort_interrupt( struct pci_controller *hose) { void __iomem *addr; - addr = (void *)hose->cfg_addr + PCI_COMMAND; + addr = hose->cfg_addr + PCI_COMMAND; out_be32(addr, in_be32(addr) | (PCI_STATUS_REC_MASTER_ABORT << 16)); } static int celleb_epci_check_abort(struct pci_controller *hose, - unsigned long addr) + void __iomem *addr) { void __iomem *reg, *epci_base; u32 val; iob(); - epci_base = (void *)hose->cfg_addr; + epci_base = hose->cfg_addr; reg = epci_base + PCI_COMMAND; val = in_be32(reg); @@ -108,23 +108,23 @@ static int celleb_epci_check_abort(struct pci_controller *hose, return PCIBIOS_SUCCESSFUL; } -static unsigned long celleb_epci_make_config_addr(struct pci_controller *hose, +static void __iomem *celleb_epci_make_config_addr(struct pci_controller *hose, unsigned int devfn, int where) { - unsigned long addr; + void __iomem *addr; struct pci_bus *bus = hose->bus; if (bus->self) - addr = (unsigned long)hose->cfg_data + + addr = hose->cfg_data + (((bus->number & 0xff) << 16) | ((devfn & 0xff) << 8) | (where & 0xff) | 0x01000000); else - addr = (unsigned long)hose->cfg_data + + addr = hose->cfg_data + (((devfn & 0xff) << 8) | (where & 0xff)); - pr_debug("EPCI: config_addr = 0x%016lx\n", addr); + pr_debug("EPCI: config_addr = 0x%p\n", addr); return addr; } @@ -132,7 +132,7 @@ static unsigned long celleb_epci_make_config_addr(struct pci_controller *hose, static int celleb_epci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) { - unsigned long addr; + void __iomem *addr; struct device_node *node; struct pci_controller *hose; @@ -148,17 +148,17 @@ static int celleb_epci_read_config(struct pci_bus *bus, if (bus->number == hose->first_busno && devfn == 0) { /* EPCI controller self */ - addr = (unsigned long)hose->cfg_addr + where; + addr = hose->cfg_addr + where; switch (size) { case 1: - *val = in_8((u8 *)addr); + *val = in_8(addr); break; case 2: - *val = in_be16((u16 *)addr); + *val = in_be16(addr); break; case 4: - *val = in_be32((u32 *)addr); + *val = in_be32(addr); break; default: return PCIBIOS_DEVICE_NOT_FOUND; @@ -171,13 +171,13 @@ static int celleb_epci_read_config(struct pci_bus *bus, switch (size) { case 1: - *val = in_8((u8 *)addr); + *val = in_8(addr); break; case 2: - *val = in_le16((u16 *)addr); + *val = in_le16(addr); break; case 4: - *val = in_le32((u32 *)addr); + *val = in_le32(addr); break; default: return PCIBIOS_DEVICE_NOT_FOUND; @@ -188,13 +188,13 @@ static int celleb_epci_read_config(struct pci_bus *bus, "addr=0x%lx, devfn=0x%x, where=0x%x, size=0x%x, val=0x%x\n", addr, devfn, where, size, *val); - return celleb_epci_check_abort(hose, 0); + return celleb_epci_check_abort(hose, NULL); } static int celleb_epci_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - unsigned long addr; + void __iomem *addr; struct device_node *node; struct pci_controller *hose; @@ -210,17 +210,17 @@ static int celleb_epci_write_config(struct pci_bus *bus, if (bus->number == hose->first_busno && devfn == 0) { /* EPCI controller self */ - addr = (unsigned long)hose->cfg_addr + where; + addr = hose->cfg_addr + where; switch (size) { case 1: - out_8((u8 *)addr, val); + out_8(addr, val); break; case 2: - out_be16((u16 *)addr, val); + out_be16(addr, val); break; case 4: - out_be32((u32 *)addr, val); + out_be32(addr, val); break; default: return PCIBIOS_DEVICE_NOT_FOUND; @@ -233,13 +233,13 @@ static int celleb_epci_write_config(struct pci_bus *bus, switch (size) { case 1: - out_8((u8 *)addr, val); + out_8(addr, val); break; case 2: - out_le16((u16 *)addr, val); + out_le16(addr, val); break; case 4: - out_le32((u32 *)addr, val); + out_le32(addr, val); break; default: return PCIBIOS_DEVICE_NOT_FOUND; @@ -261,7 +261,7 @@ static int __devinit celleb_epci_init(struct pci_controller *hose) void __iomem *reg, *epci_base; int hwres = 0; - epci_base = (void *)hose->cfg_addr; + epci_base = hose->cfg_addr; /* PCI core reset(Internal bus and PCI clock) */ reg = epci_base + SCC_EPCI_CKCTRL; diff --git a/trunk/arch/powerpc/platforms/chrp/setup.c b/trunk/arch/powerpc/platforms/chrp/setup.c index e1f51d455984..117c9a0055bd 100644 --- a/trunk/arch/powerpc/platforms/chrp/setup.c +++ b/trunk/arch/powerpc/platforms/chrp/setup.c @@ -75,7 +75,7 @@ extern irqreturn_t xmon_irq(int, void *); extern unsigned long loops_per_jiffy; /* To be replaced by RTAS when available */ -static unsigned int *briq_SPOR; +static unsigned int __iomem *briq_SPOR; #ifdef CONFIG_SMP extern struct smp_ops_t chrp_smp_ops; @@ -267,7 +267,7 @@ void __init chrp_setup_arch(void) } else if (machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0) { _chrp_type = _CHRP_briq; /* Map the SPOR register on briq and change the restart hook */ - briq_SPOR = (unsigned int *)ioremap(0xff0000e8, 4); + briq_SPOR = ioremap(0xff0000e8, 4); ppc_md.restart = briq_restart; } else { /* Let's assume it is an IBM chrp if all else fails */ diff --git a/trunk/arch/powerpc/platforms/ps3/interrupt.c b/trunk/arch/powerpc/platforms/ps3/interrupt.c index bb17283275aa..631c30095617 100644 --- a/trunk/arch/powerpc/platforms/ps3/interrupt.c +++ b/trunk/arch/powerpc/platforms/ps3/interrupt.c @@ -194,6 +194,7 @@ int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id, return result; } +EXPORT_SYMBOL_GPL(ps3_alloc_io_irq); int ps3_free_io_irq(unsigned int virq) { @@ -209,6 +210,7 @@ int ps3_free_io_irq(unsigned int virq) return result; } +EXPORT_SYMBOL_GPL(ps3_free_io_irq); /** * ps3_alloc_event_irq - Allocate a virq for use with a system event. diff --git a/trunk/arch/powerpc/platforms/ps3/system-bus.c b/trunk/arch/powerpc/platforms/ps3/system-bus.c index bce6136cbce7..a9f7e4a39a2a 100644 --- a/trunk/arch/powerpc/platforms/ps3/system-bus.c +++ b/trunk/arch/powerpc/platforms/ps3/system-bus.c @@ -57,6 +57,7 @@ int ps3_mmio_region_create(struct ps3_mmio_region *r) dump_mmio_region(r); return result; } +EXPORT_SYMBOL_GPL(ps3_mmio_region_create); int ps3_free_mmio_region(struct ps3_mmio_region *r) { @@ -72,6 +73,7 @@ int ps3_free_mmio_region(struct ps3_mmio_region *r) r->lpar_addr = 0; return result; } +EXPORT_SYMBOL_GPL(ps3_free_mmio_region); static int ps3_system_bus_match(struct device *_dev, struct device_driver *_drv) diff --git a/trunk/arch/powerpc/xmon/spu-dis.c b/trunk/arch/powerpc/xmon/spu-dis.c index ee929c641bf3..e5f89837c82e 100644 --- a/trunk/arch/powerpc/xmon/spu-dis.c +++ b/trunk/arch/powerpc/xmon/spu-dis.c @@ -85,7 +85,7 @@ get_index_for_opcode (unsigned int insn) if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0) return index; - return 0; + return NULL; } /* Print a Spu instruction. */ diff --git a/trunk/arch/s390/defconfig b/trunk/arch/s390/defconfig index 7c621b8ef683..1406400bf3ea 100644 --- a/trunk/arch/s390/defconfig +++ b/trunk/arch/s390/defconfig @@ -179,6 +179,8 @@ CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set CONFIG_NET_KEY=y +CONFIG_IUCV=m +CONFIG_AFIUCV=m CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set @@ -508,7 +510,6 @@ CONFIG_NET_ETHERNET=y # CONFIG_LCS=m CONFIG_CTC=m -CONFIG_IUCV=m # CONFIG_NETIUCV is not set # CONFIG_SMSGIUCV is not set # CONFIG_CLAW is not set diff --git a/trunk/arch/sh/kernel/vsyscall/vsyscall.c b/trunk/arch/sh/kernel/vsyscall/vsyscall.c index deb46941f315..7b0f66f03319 100644 --- a/trunk/arch/sh/kernel/vsyscall/vsyscall.c +++ b/trunk/arch/sh/kernel/vsyscall/vsyscall.c @@ -37,11 +37,12 @@ __setup("vdso=", vdso_setup); * of the ELF DSO images included therein. */ extern const char vsyscall_trapa_start, vsyscall_trapa_end; -static void *syscall_page; +static struct page *syscall_pages[1]; int __init vsyscall_init(void) { - syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + syscall_pages[0] = virt_to_page(syscall_page); /* * XXX: Map this page to a fixmap entry if we get around @@ -55,37 +56,10 @@ int __init vsyscall_init(void) return 0; } -static struct page *syscall_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) -{ - unsigned long offset = address - vma->vm_start; - struct page *page; - - if (address < vma->vm_start || address > vma->vm_end) - return NOPAGE_SIGBUS; - - page = virt_to_page(syscall_page + offset); - - get_page(page); - - return page; -} - -/* Prevent VMA merging */ -static void syscall_vma_close(struct vm_area_struct *vma) -{ -} - -static struct vm_operations_struct syscall_vm_ops = { - .nopage = syscall_vma_nopage, - .close = syscall_vma_close, -}; - /* Setup a VMA at program startup for the vsyscall page */ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) { - struct vm_area_struct *vma; struct mm_struct *mm = current->mm; unsigned long addr; int ret; @@ -97,30 +71,16 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, goto up_fail; } - vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (!vma) { - ret = -ENOMEM; + ret = install_special_mapping(mm, addr, PAGE_SIZE, + VM_READ | VM_EXEC | + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | + VM_ALWAYSDUMP, + syscall_pages); + if (unlikely(ret)) goto up_fail; - } - - vma->vm_start = addr; - vma->vm_end = addr + PAGE_SIZE; - /* MAYWRITE to allow gdb to COW and set breakpoints */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; - vma->vm_flags |= mm->def_flags; - vma->vm_page_prot = protection_map[vma->vm_flags & 7]; - vma->vm_ops = &syscall_vm_ops; - vma->vm_mm = mm; - - ret = insert_vm_struct(mm, vma); - if (unlikely(ret)) { - kmem_cache_free(vm_area_cachep, vma); - goto up_fail; - } current->mm->context.vdso = (void *)addr; - mm->total_vm++; up_fail: up_write(&mm->mmap_sem); return ret; diff --git a/trunk/arch/x86_64/ia32/syscall32.c b/trunk/arch/x86_64/ia32/syscall32.c index 59f1fa155915..568ff0df89e7 100644 --- a/trunk/arch/x86_64/ia32/syscall32.c +++ b/trunk/arch/x86_64/ia32/syscall32.c @@ -18,68 +18,34 @@ extern unsigned char syscall32_syscall[], syscall32_syscall_end[]; extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[]; extern int sysctl_vsyscall32; -char *syscall32_page; +static struct page *syscall32_pages[1]; static int use_sysenter = -1; -static struct page * -syscall32_nopage(struct vm_area_struct *vma, unsigned long adr, int *type) -{ - struct page *p = virt_to_page(adr - vma->vm_start + syscall32_page); - get_page(p); - return p; -} - -/* Prevent VMA merging */ -static void syscall32_vma_close(struct vm_area_struct *vma) -{ -} - -static struct vm_operations_struct syscall32_vm_ops = { - .close = syscall32_vma_close, - .nopage = syscall32_nopage, -}; - struct linux_binprm; /* Setup a VMA at program startup for the vsyscall page */ int syscall32_setup_pages(struct linux_binprm *bprm, int exstack) { - int npages = (VSYSCALL32_END - VSYSCALL32_BASE) >> PAGE_SHIFT; - struct vm_area_struct *vma; struct mm_struct *mm = current->mm; int ret; - vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); - if (!vma) - return -ENOMEM; - - memset(vma, 0, sizeof(struct vm_area_struct)); - /* Could randomize here */ - vma->vm_start = VSYSCALL32_BASE; - vma->vm_end = VSYSCALL32_END; - /* MAYWRITE to allow gdb to COW and set breakpoints */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; + down_write(&mm->mmap_sem); /* + * MAYWRITE to allow gdb to COW and set breakpoints + * * Make sure the vDSO gets into every core dump. * Dumping its contents makes post-mortem fully interpretable later * without matching up the same kernel and hardware config to see * what PC values meant. */ - vma->vm_flags |= VM_ALWAYSDUMP; - vma->vm_flags |= mm->def_flags; - vma->vm_page_prot = protection_map[vma->vm_flags & 7]; - vma->vm_ops = &syscall32_vm_ops; - vma->vm_mm = mm; - - down_write(&mm->mmap_sem); - if ((ret = insert_vm_struct(mm, vma))) { - up_write(&mm->mmap_sem); - kmem_cache_free(vm_area_cachep, vma); - return ret; - } - mm->total_vm += npages; + /* Could randomize here */ + ret = install_special_mapping(mm, VSYSCALL32_BASE, PAGE_SIZE, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + syscall32_pages); up_write(&mm->mmap_sem); - return 0; + return ret; } const char *arch_vma_name(struct vm_area_struct *vma) @@ -92,9 +58,10 @@ const char *arch_vma_name(struct vm_area_struct *vma) static int __init init_syscall32(void) { - syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); + char *syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); if (!syscall32_page) panic("Cannot allocate syscall32 page"); + syscall32_pages[0] = virt_to_page(syscall32_page); if (use_sysenter > 0) { memcpy(syscall32_page, syscall32_sysenter, syscall32_sysenter_end - syscall32_sysenter); diff --git a/trunk/block/ll_rw_blk.c b/trunk/block/ll_rw_blk.c index fb6789725e1b..38c293b987b7 100644 --- a/trunk/block/ll_rw_blk.c +++ b/trunk/block/ll_rw_blk.c @@ -1264,7 +1264,7 @@ void blk_recount_segments(request_queue_t *q, struct bio *bio) bio->bi_hw_segments = nr_hw_segs; bio->bi_flags |= (1 << BIO_SEG_VALID); } - +EXPORT_SYMBOL(blk_recount_segments); static int blk_phys_contig_segment(request_queue_t *q, struct bio *bio, struct bio *nxt) diff --git a/trunk/crypto/Kconfig b/trunk/crypto/Kconfig index 918b4d845f93..086fcec44720 100644 --- a/trunk/crypto/Kconfig +++ b/trunk/crypto/Kconfig @@ -149,6 +149,15 @@ config CRYPTO_CBC CBC: Cipher Block Chaining mode This block cipher algorithm is required for IPSec. +config CRYPTO_PCBC + tristate "PCBC support" + select CRYPTO_BLKCIPHER + select CRYPTO_MANAGER + default m + help + PCBC: Propagating Cipher Block Chaining mode + This block cipher algorithm is required for RxRPC. + config CRYPTO_LRW tristate "LRW support (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -168,6 +177,13 @@ config CRYPTO_DES help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). +config CRYPTO_FCRYPT + tristate "FCrypt cipher algorithm" + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + FCrypt algorithm used by RxRPC. + config CRYPTO_BLOWFISH tristate "Blowfish cipher algorithm" select CRYPTO_ALGAPI @@ -409,6 +425,21 @@ config CRYPTO_CRC32C See Castagnoli93. This implementation uses lib/libcrc32c. Module will be crc32c. +config CRYPTO_CAMELLIA + tristate "Camellia cipher algorithms" + depends on CRYPTO + select CRYPTO_ALGAPI + help + Camellia cipher algorithms module. + + Camellia is a symmetric key block cipher developed jointly + at NTT and Mitsubishi Electric Corporation. + + The Camellia specifies three key sizes: 128, 192 and 256 bits. + + See also: + + config CRYPTO_TEST tristate "Testing module" depends on m diff --git a/trunk/crypto/Makefile b/trunk/crypto/Makefile index 60e3d24f61f5..12f93f578171 100644 --- a/trunk/crypto/Makefile +++ b/trunk/crypto/Makefile @@ -27,13 +27,16 @@ obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o obj-$(CONFIG_CRYPTO_ECB) += ecb.o obj-$(CONFIG_CRYPTO_CBC) += cbc.o +obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o obj-$(CONFIG_CRYPTO_DES) += des.o +obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o obj-$(CONFIG_CRYPTO_AES) += aes.o +obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o diff --git a/trunk/crypto/algapi.c b/trunk/crypto/algapi.c index c91530021e9c..f7d2185b2c8f 100644 --- a/trunk/crypto/algapi.c +++ b/trunk/crypto/algapi.c @@ -377,7 +377,8 @@ void crypto_drop_spawn(struct crypto_spawn *spawn) } EXPORT_SYMBOL_GPL(crypto_drop_spawn); -struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn) +struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, + u32 mask) { struct crypto_alg *alg; struct crypto_alg *alg2; @@ -396,10 +397,18 @@ struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn) return ERR_PTR(-EAGAIN); } - tfm = __crypto_alloc_tfm(alg, 0); + tfm = ERR_PTR(-EINVAL); + if (unlikely((alg->cra_flags ^ type) & mask)) + goto out_put_alg; + + tfm = __crypto_alloc_tfm(alg, type, mask); if (IS_ERR(tfm)) - crypto_mod_put(alg); + goto out_put_alg; + + return tfm; +out_put_alg: + crypto_mod_put(alg); return tfm; } EXPORT_SYMBOL_GPL(crypto_spawn_tfm); diff --git a/trunk/crypto/api.c b/trunk/crypto/api.c index 8c446871cd5b..55af8bb0f050 100644 --- a/trunk/crypto/api.c +++ b/trunk/crypto/api.c @@ -212,31 +212,12 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup); -static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) +static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { - tfm->crt_flags = flags & CRYPTO_TFM_REQ_MASK; - flags &= ~CRYPTO_TFM_REQ_MASK; - - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - return crypto_init_cipher_flags(tfm, flags); - - case CRYPTO_ALG_TYPE_DIGEST: - return crypto_init_digest_flags(tfm, flags); - - case CRYPTO_ALG_TYPE_COMPRESS: - return crypto_init_compress_flags(tfm, flags); - } - - return 0; -} + const struct crypto_type *type_obj = tfm->__crt_alg->cra_type; -static int crypto_init_ops(struct crypto_tfm *tfm) -{ - const struct crypto_type *type = tfm->__crt_alg->cra_type; - - if (type) - return type->init(tfm); + if (type_obj) + return type_obj->init(tfm, type, mask); switch (crypto_tfm_alg_type(tfm)) { case CRYPTO_ALG_TYPE_CIPHER: @@ -285,29 +266,29 @@ static void crypto_exit_ops(struct crypto_tfm *tfm) } } -static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) +static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) { - const struct crypto_type *type = alg->cra_type; + const struct crypto_type *type_obj = alg->cra_type; unsigned int len; len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1); - if (type) - return len + type->ctxsize(alg); + if (type_obj) + return len + type_obj->ctxsize(alg, type, mask); switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { default: BUG(); case CRYPTO_ALG_TYPE_CIPHER: - len += crypto_cipher_ctxsize(alg, flags); + len += crypto_cipher_ctxsize(alg); break; case CRYPTO_ALG_TYPE_DIGEST: - len += crypto_digest_ctxsize(alg, flags); + len += crypto_digest_ctxsize(alg); break; case CRYPTO_ALG_TYPE_COMPRESS: - len += crypto_compress_ctxsize(alg, flags); + len += crypto_compress_ctxsize(alg); break; } @@ -322,24 +303,21 @@ void crypto_shoot_alg(struct crypto_alg *alg) } EXPORT_SYMBOL_GPL(crypto_shoot_alg); -struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags) +struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, + u32 mask) { struct crypto_tfm *tfm = NULL; unsigned int tfm_size; int err = -ENOMEM; - tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); + tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask); tfm = kzalloc(tfm_size, GFP_KERNEL); if (tfm == NULL) goto out_err; tfm->__crt_alg = alg; - err = crypto_init_flags(tfm, flags); - if (err) - goto out_free_tfm; - - err = crypto_init_ops(tfm); + err = crypto_init_ops(tfm, type, mask); if (err) goto out_free_tfm; @@ -362,31 +340,6 @@ struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags) } EXPORT_SYMBOL_GPL(__crypto_alloc_tfm); -struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) -{ - struct crypto_tfm *tfm = NULL; - int err; - - do { - struct crypto_alg *alg; - - alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC); - err = PTR_ERR(alg); - if (IS_ERR(alg)) - continue; - - tfm = __crypto_alloc_tfm(alg, flags); - err = 0; - if (IS_ERR(tfm)) { - crypto_mod_put(alg); - err = PTR_ERR(tfm); - tfm = NULL; - } - } while (err == -EAGAIN && !signal_pending(current)); - - return tfm; -} - /* * crypto_alloc_base - Locate algorithm and allocate transform * @alg_name: Name of algorithm @@ -420,7 +373,7 @@ struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) goto err; } - tfm = __crypto_alloc_tfm(alg, 0); + tfm = __crypto_alloc_tfm(alg, type, mask); if (!IS_ERR(tfm)) return tfm; @@ -466,7 +419,6 @@ void crypto_free_tfm(struct crypto_tfm *tfm) kfree(tfm); } -EXPORT_SYMBOL_GPL(crypto_alloc_tfm); EXPORT_SYMBOL_GPL(crypto_free_tfm); int crypto_has_alg(const char *name, u32 type, u32 mask) diff --git a/trunk/crypto/blkcipher.c b/trunk/crypto/blkcipher.c index 6e93004f2181..b5befe8c3a96 100644 --- a/trunk/crypto/blkcipher.c +++ b/trunk/crypto/blkcipher.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -313,6 +314,9 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc, struct crypto_blkcipher *tfm = desc->tfm; unsigned int alignmask = crypto_blkcipher_alignmask(tfm); + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + walk->nbytes = walk->total; if (unlikely(!walk->total)) return 0; @@ -345,7 +349,8 @@ static int setkey(struct crypto_tfm *tfm, const u8 *key, return cipher->setkey(tfm, key, keylen); } -static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg) +static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type, + u32 mask) { struct blkcipher_alg *cipher = &alg->cra_blkcipher; unsigned int len = alg->cra_ctxsize; @@ -358,7 +363,7 @@ static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg) return len; } -static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm) +static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { struct blkcipher_tfm *crt = &tfm->crt_blkcipher; struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; diff --git a/trunk/crypto/camellia.c b/trunk/crypto/camellia.c new file mode 100644 index 000000000000..6877ecfd90bb --- /dev/null +++ b/trunk/crypto/camellia.c @@ -0,0 +1,1801 @@ +/* + * Copyright (C) 2006 + * NTT (Nippon Telegraph and Telephone Corporation). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Algorithm Specification + * http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html + */ + +/* + * + * NOTE --- NOTE --- NOTE --- NOTE + * This implementation assumes that all memory addresses passed + * as parameters are four-byte aligned. + * + */ + +#include +#include +#include +#include +#include + + +#define CAMELLIA_MIN_KEY_SIZE 16 +#define CAMELLIA_MAX_KEY_SIZE 32 +#define CAMELLIA_BLOCK_SIZE 16 +#define CAMELLIA_TABLE_BYTE_LEN 272 +#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4) + +typedef u32 KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; + + +/* key constants */ + +#define CAMELLIA_SIGMA1L (0xA09E667FL) +#define CAMELLIA_SIGMA1R (0x3BCC908BL) +#define CAMELLIA_SIGMA2L (0xB67AE858L) +#define CAMELLIA_SIGMA2R (0x4CAA73B2L) +#define CAMELLIA_SIGMA3L (0xC6EF372FL) +#define CAMELLIA_SIGMA3R (0xE94F82BEL) +#define CAMELLIA_SIGMA4L (0x54FF53A5L) +#define CAMELLIA_SIGMA4R (0xF1D36F1CL) +#define CAMELLIA_SIGMA5L (0x10E527FAL) +#define CAMELLIA_SIGMA5R (0xDE682D1DL) +#define CAMELLIA_SIGMA6L (0xB05688C2L) +#define CAMELLIA_SIGMA6R (0xB3E6C1FDL) + +struct camellia_ctx { + int key_length; + KEY_TABLE_TYPE key_table; +}; + + +/* + * macros + */ + + +# define GETU32(pt) (((u32)(pt)[0] << 24) \ + ^ ((u32)(pt)[1] << 16) \ + ^ ((u32)(pt)[2] << 8) \ + ^ ((u32)(pt)[3])) + +#define COPY4WORD(dst, src) \ + do { \ + (dst)[0]=(src)[0]; \ + (dst)[1]=(src)[1]; \ + (dst)[2]=(src)[2]; \ + (dst)[3]=(src)[3]; \ + }while(0) + +#define SWAP4WORD(word) \ + do { \ + CAMELLIA_SWAP4((word)[0]); \ + CAMELLIA_SWAP4((word)[1]); \ + CAMELLIA_SWAP4((word)[2]); \ + CAMELLIA_SWAP4((word)[3]); \ + }while(0) + +#define XOR4WORD(a, b)/* a = a ^ b */ \ + do { \ + (a)[0]^=(b)[0]; \ + (a)[1]^=(b)[1]; \ + (a)[2]^=(b)[2]; \ + (a)[3]^=(b)[3]; \ + }while(0) + +#define XOR4WORD2(a, b, c)/* a = b ^ c */ \ + do { \ + (a)[0]=(b)[0]^(c)[0]; \ + (a)[1]=(b)[1]^(c)[1]; \ + (a)[2]=(b)[2]^(c)[2]; \ + (a)[3]=(b)[3]^(c)[3]; \ + }while(0) + +#define CAMELLIA_SUBKEY_L(INDEX) (subkey[(INDEX)*2]) +#define CAMELLIA_SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1]) + +/* rotation right shift 1byte */ +#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24)) +/* rotation left shift 1bit */ +#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31)) +/* rotation left shift 1byte */ +#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24)) + +#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + ll = (ll << bits) + (lr >> (32 - bits)); \ + lr = (lr << bits) + (rl >> (32 - bits)); \ + rl = (rl << bits) + (rr >> (32 - bits)); \ + rr = (rr << bits) + (w0 >> (32 - bits)); \ + } while(0) + +#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + w1 = lr; \ + ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \ + lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \ + rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \ + rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \ + } while(0) + +#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)]) +#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)]) +#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)]) +#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)]) + +#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ + il = xl ^ kl; \ + ir = xr ^ kr; \ + t0 = il >> 16; \ + t1 = ir >> 16; \ + yl = CAMELLIA_SP1110(ir & 0xff) \ + ^ CAMELLIA_SP0222((t1 >> 8) & 0xff) \ + ^ CAMELLIA_SP3033(t1 & 0xff) \ + ^ CAMELLIA_SP4404((ir >> 8) & 0xff); \ + yr = CAMELLIA_SP1110((t0 >> 8) & 0xff) \ + ^ CAMELLIA_SP0222(t0 & 0xff) \ + ^ CAMELLIA_SP3033((il >> 8) & 0xff) \ + ^ CAMELLIA_SP4404(il & 0xff); \ + yl ^= yr; \ + yr = CAMELLIA_RR8(yr); \ + yr ^= yl; \ + } while(0) + + +/* + * for speed up + * + */ +#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \ + do { \ + t0 = kll; \ + t2 = krr; \ + t0 &= ll; \ + t2 |= rr; \ + rl ^= t2; \ + lr ^= CAMELLIA_RL1(t0); \ + t3 = krl; \ + t1 = klr; \ + t3 &= rl; \ + t1 |= lr; \ + ll ^= t1; \ + rr ^= CAMELLIA_RL1(t3); \ + } while(0) + +#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ + ir = CAMELLIA_SP1110(xr & 0xff); \ + il = CAMELLIA_SP1110((xl>>24) & 0xff); \ + ir ^= CAMELLIA_SP0222((xr>>24) & 0xff); \ + il ^= CAMELLIA_SP0222((xl>>16) & 0xff); \ + ir ^= CAMELLIA_SP3033((xr>>16) & 0xff); \ + il ^= CAMELLIA_SP3033((xl>>8) & 0xff); \ + ir ^= CAMELLIA_SP4404((xr>>8) & 0xff); \ + il ^= CAMELLIA_SP4404(xl & 0xff); \ + il ^= kl; \ + ir ^= il ^ kr; \ + yl ^= ir; \ + yr ^= CAMELLIA_RR8(il) ^ ir; \ + } while(0) + +/** + * Stuff related to the Camellia key schedule + */ +#define SUBL(x) subL[(x)] +#define SUBR(x) subR[(x)] + + +static const u32 camellia_sp1110[256] = { + 0x70707000,0x82828200,0x2c2c2c00,0xececec00, + 0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500, + 0xe4e4e400,0x85858500,0x57575700,0x35353500, + 0xeaeaea00,0x0c0c0c00,0xaeaeae00,0x41414100, + 0x23232300,0xefefef00,0x6b6b6b00,0x93939300, + 0x45454500,0x19191900,0xa5a5a500,0x21212100, + 0xededed00,0x0e0e0e00,0x4f4f4f00,0x4e4e4e00, + 0x1d1d1d00,0x65656500,0x92929200,0xbdbdbd00, + 0x86868600,0xb8b8b800,0xafafaf00,0x8f8f8f00, + 0x7c7c7c00,0xebebeb00,0x1f1f1f00,0xcecece00, + 0x3e3e3e00,0x30303000,0xdcdcdc00,0x5f5f5f00, + 0x5e5e5e00,0xc5c5c500,0x0b0b0b00,0x1a1a1a00, + 0xa6a6a600,0xe1e1e100,0x39393900,0xcacaca00, + 0xd5d5d500,0x47474700,0x5d5d5d00,0x3d3d3d00, + 0xd9d9d900,0x01010100,0x5a5a5a00,0xd6d6d600, + 0x51515100,0x56565600,0x6c6c6c00,0x4d4d4d00, + 0x8b8b8b00,0x0d0d0d00,0x9a9a9a00,0x66666600, + 0xfbfbfb00,0xcccccc00,0xb0b0b000,0x2d2d2d00, + 0x74747400,0x12121200,0x2b2b2b00,0x20202000, + 0xf0f0f000,0xb1b1b100,0x84848400,0x99999900, + 0xdfdfdf00,0x4c4c4c00,0xcbcbcb00,0xc2c2c200, + 0x34343400,0x7e7e7e00,0x76767600,0x05050500, + 0x6d6d6d00,0xb7b7b700,0xa9a9a900,0x31313100, + 0xd1d1d100,0x17171700,0x04040400,0xd7d7d700, + 0x14141400,0x58585800,0x3a3a3a00,0x61616100, + 0xdedede00,0x1b1b1b00,0x11111100,0x1c1c1c00, + 0x32323200,0x0f0f0f00,0x9c9c9c00,0x16161600, + 0x53535300,0x18181800,0xf2f2f200,0x22222200, + 0xfefefe00,0x44444400,0xcfcfcf00,0xb2b2b200, + 0xc3c3c300,0xb5b5b500,0x7a7a7a00,0x91919100, + 0x24242400,0x08080800,0xe8e8e800,0xa8a8a800, + 0x60606000,0xfcfcfc00,0x69696900,0x50505000, + 0xaaaaaa00,0xd0d0d000,0xa0a0a000,0x7d7d7d00, + 0xa1a1a100,0x89898900,0x62626200,0x97979700, + 0x54545400,0x5b5b5b00,0x1e1e1e00,0x95959500, + 0xe0e0e000,0xffffff00,0x64646400,0xd2d2d200, + 0x10101000,0xc4c4c400,0x00000000,0x48484800, + 0xa3a3a300,0xf7f7f700,0x75757500,0xdbdbdb00, + 0x8a8a8a00,0x03030300,0xe6e6e600,0xdadada00, + 0x09090900,0x3f3f3f00,0xdddddd00,0x94949400, + 0x87878700,0x5c5c5c00,0x83838300,0x02020200, + 0xcdcdcd00,0x4a4a4a00,0x90909000,0x33333300, + 0x73737300,0x67676700,0xf6f6f600,0xf3f3f300, + 0x9d9d9d00,0x7f7f7f00,0xbfbfbf00,0xe2e2e200, + 0x52525200,0x9b9b9b00,0xd8d8d800,0x26262600, + 0xc8c8c800,0x37373700,0xc6c6c600,0x3b3b3b00, + 0x81818100,0x96969600,0x6f6f6f00,0x4b4b4b00, + 0x13131300,0xbebebe00,0x63636300,0x2e2e2e00, + 0xe9e9e900,0x79797900,0xa7a7a700,0x8c8c8c00, + 0x9f9f9f00,0x6e6e6e00,0xbcbcbc00,0x8e8e8e00, + 0x29292900,0xf5f5f500,0xf9f9f900,0xb6b6b600, + 0x2f2f2f00,0xfdfdfd00,0xb4b4b400,0x59595900, + 0x78787800,0x98989800,0x06060600,0x6a6a6a00, + 0xe7e7e700,0x46464600,0x71717100,0xbababa00, + 0xd4d4d400,0x25252500,0xababab00,0x42424200, + 0x88888800,0xa2a2a200,0x8d8d8d00,0xfafafa00, + 0x72727200,0x07070700,0xb9b9b900,0x55555500, + 0xf8f8f800,0xeeeeee00,0xacacac00,0x0a0a0a00, + 0x36363600,0x49494900,0x2a2a2a00,0x68686800, + 0x3c3c3c00,0x38383800,0xf1f1f100,0xa4a4a400, + 0x40404000,0x28282800,0xd3d3d300,0x7b7b7b00, + 0xbbbbbb00,0xc9c9c900,0x43434300,0xc1c1c100, + 0x15151500,0xe3e3e300,0xadadad00,0xf4f4f400, + 0x77777700,0xc7c7c700,0x80808000,0x9e9e9e00, +}; + +static const u32 camellia_sp0222[256] = { + 0x00e0e0e0,0x00050505,0x00585858,0x00d9d9d9, + 0x00676767,0x004e4e4e,0x00818181,0x00cbcbcb, + 0x00c9c9c9,0x000b0b0b,0x00aeaeae,0x006a6a6a, + 0x00d5d5d5,0x00181818,0x005d5d5d,0x00828282, + 0x00464646,0x00dfdfdf,0x00d6d6d6,0x00272727, + 0x008a8a8a,0x00323232,0x004b4b4b,0x00424242, + 0x00dbdbdb,0x001c1c1c,0x009e9e9e,0x009c9c9c, + 0x003a3a3a,0x00cacaca,0x00252525,0x007b7b7b, + 0x000d0d0d,0x00717171,0x005f5f5f,0x001f1f1f, + 0x00f8f8f8,0x00d7d7d7,0x003e3e3e,0x009d9d9d, + 0x007c7c7c,0x00606060,0x00b9b9b9,0x00bebebe, + 0x00bcbcbc,0x008b8b8b,0x00161616,0x00343434, + 0x004d4d4d,0x00c3c3c3,0x00727272,0x00959595, + 0x00ababab,0x008e8e8e,0x00bababa,0x007a7a7a, + 0x00b3b3b3,0x00020202,0x00b4b4b4,0x00adadad, + 0x00a2a2a2,0x00acacac,0x00d8d8d8,0x009a9a9a, + 0x00171717,0x001a1a1a,0x00353535,0x00cccccc, + 0x00f7f7f7,0x00999999,0x00616161,0x005a5a5a, + 0x00e8e8e8,0x00242424,0x00565656,0x00404040, + 0x00e1e1e1,0x00636363,0x00090909,0x00333333, + 0x00bfbfbf,0x00989898,0x00979797,0x00858585, + 0x00686868,0x00fcfcfc,0x00ececec,0x000a0a0a, + 0x00dadada,0x006f6f6f,0x00535353,0x00626262, + 0x00a3a3a3,0x002e2e2e,0x00080808,0x00afafaf, + 0x00282828,0x00b0b0b0,0x00747474,0x00c2c2c2, + 0x00bdbdbd,0x00363636,0x00222222,0x00383838, + 0x00646464,0x001e1e1e,0x00393939,0x002c2c2c, + 0x00a6a6a6,0x00303030,0x00e5e5e5,0x00444444, + 0x00fdfdfd,0x00888888,0x009f9f9f,0x00656565, + 0x00878787,0x006b6b6b,0x00f4f4f4,0x00232323, + 0x00484848,0x00101010,0x00d1d1d1,0x00515151, + 0x00c0c0c0,0x00f9f9f9,0x00d2d2d2,0x00a0a0a0, + 0x00555555,0x00a1a1a1,0x00414141,0x00fafafa, + 0x00434343,0x00131313,0x00c4c4c4,0x002f2f2f, + 0x00a8a8a8,0x00b6b6b6,0x003c3c3c,0x002b2b2b, + 0x00c1c1c1,0x00ffffff,0x00c8c8c8,0x00a5a5a5, + 0x00202020,0x00898989,0x00000000,0x00909090, + 0x00474747,0x00efefef,0x00eaeaea,0x00b7b7b7, + 0x00151515,0x00060606,0x00cdcdcd,0x00b5b5b5, + 0x00121212,0x007e7e7e,0x00bbbbbb,0x00292929, + 0x000f0f0f,0x00b8b8b8,0x00070707,0x00040404, + 0x009b9b9b,0x00949494,0x00212121,0x00666666, + 0x00e6e6e6,0x00cecece,0x00ededed,0x00e7e7e7, + 0x003b3b3b,0x00fefefe,0x007f7f7f,0x00c5c5c5, + 0x00a4a4a4,0x00373737,0x00b1b1b1,0x004c4c4c, + 0x00919191,0x006e6e6e,0x008d8d8d,0x00767676, + 0x00030303,0x002d2d2d,0x00dedede,0x00969696, + 0x00262626,0x007d7d7d,0x00c6c6c6,0x005c5c5c, + 0x00d3d3d3,0x00f2f2f2,0x004f4f4f,0x00191919, + 0x003f3f3f,0x00dcdcdc,0x00797979,0x001d1d1d, + 0x00525252,0x00ebebeb,0x00f3f3f3,0x006d6d6d, + 0x005e5e5e,0x00fbfbfb,0x00696969,0x00b2b2b2, + 0x00f0f0f0,0x00313131,0x000c0c0c,0x00d4d4d4, + 0x00cfcfcf,0x008c8c8c,0x00e2e2e2,0x00757575, + 0x00a9a9a9,0x004a4a4a,0x00575757,0x00848484, + 0x00111111,0x00454545,0x001b1b1b,0x00f5f5f5, + 0x00e4e4e4,0x000e0e0e,0x00737373,0x00aaaaaa, + 0x00f1f1f1,0x00dddddd,0x00595959,0x00141414, + 0x006c6c6c,0x00929292,0x00545454,0x00d0d0d0, + 0x00787878,0x00707070,0x00e3e3e3,0x00494949, + 0x00808080,0x00505050,0x00a7a7a7,0x00f6f6f6, + 0x00777777,0x00939393,0x00868686,0x00838383, + 0x002a2a2a,0x00c7c7c7,0x005b5b5b,0x00e9e9e9, + 0x00eeeeee,0x008f8f8f,0x00010101,0x003d3d3d, +}; + +static const u32 camellia_sp3033[256] = { + 0x38003838,0x41004141,0x16001616,0x76007676, + 0xd900d9d9,0x93009393,0x60006060,0xf200f2f2, + 0x72007272,0xc200c2c2,0xab00abab,0x9a009a9a, + 0x75007575,0x06000606,0x57005757,0xa000a0a0, + 0x91009191,0xf700f7f7,0xb500b5b5,0xc900c9c9, + 0xa200a2a2,0x8c008c8c,0xd200d2d2,0x90009090, + 0xf600f6f6,0x07000707,0xa700a7a7,0x27002727, + 0x8e008e8e,0xb200b2b2,0x49004949,0xde00dede, + 0x43004343,0x5c005c5c,0xd700d7d7,0xc700c7c7, + 0x3e003e3e,0xf500f5f5,0x8f008f8f,0x67006767, + 0x1f001f1f,0x18001818,0x6e006e6e,0xaf00afaf, + 0x2f002f2f,0xe200e2e2,0x85008585,0x0d000d0d, + 0x53005353,0xf000f0f0,0x9c009c9c,0x65006565, + 0xea00eaea,0xa300a3a3,0xae00aeae,0x9e009e9e, + 0xec00ecec,0x80008080,0x2d002d2d,0x6b006b6b, + 0xa800a8a8,0x2b002b2b,0x36003636,0xa600a6a6, + 0xc500c5c5,0x86008686,0x4d004d4d,0x33003333, + 0xfd00fdfd,0x66006666,0x58005858,0x96009696, + 0x3a003a3a,0x09000909,0x95009595,0x10001010, + 0x78007878,0xd800d8d8,0x42004242,0xcc00cccc, + 0xef00efef,0x26002626,0xe500e5e5,0x61006161, + 0x1a001a1a,0x3f003f3f,0x3b003b3b,0x82008282, + 0xb600b6b6,0xdb00dbdb,0xd400d4d4,0x98009898, + 0xe800e8e8,0x8b008b8b,0x02000202,0xeb00ebeb, + 0x0a000a0a,0x2c002c2c,0x1d001d1d,0xb000b0b0, + 0x6f006f6f,0x8d008d8d,0x88008888,0x0e000e0e, + 0x19001919,0x87008787,0x4e004e4e,0x0b000b0b, + 0xa900a9a9,0x0c000c0c,0x79007979,0x11001111, + 0x7f007f7f,0x22002222,0xe700e7e7,0x59005959, + 0xe100e1e1,0xda00dada,0x3d003d3d,0xc800c8c8, + 0x12001212,0x04000404,0x74007474,0x54005454, + 0x30003030,0x7e007e7e,0xb400b4b4,0x28002828, + 0x55005555,0x68006868,0x50005050,0xbe00bebe, + 0xd000d0d0,0xc400c4c4,0x31003131,0xcb00cbcb, + 0x2a002a2a,0xad00adad,0x0f000f0f,0xca00caca, + 0x70007070,0xff00ffff,0x32003232,0x69006969, + 0x08000808,0x62006262,0x00000000,0x24002424, + 0xd100d1d1,0xfb00fbfb,0xba00baba,0xed00eded, + 0x45004545,0x81008181,0x73007373,0x6d006d6d, + 0x84008484,0x9f009f9f,0xee00eeee,0x4a004a4a, + 0xc300c3c3,0x2e002e2e,0xc100c1c1,0x01000101, + 0xe600e6e6,0x25002525,0x48004848,0x99009999, + 0xb900b9b9,0xb300b3b3,0x7b007b7b,0xf900f9f9, + 0xce00cece,0xbf00bfbf,0xdf00dfdf,0x71007171, + 0x29002929,0xcd00cdcd,0x6c006c6c,0x13001313, + 0x64006464,0x9b009b9b,0x63006363,0x9d009d9d, + 0xc000c0c0,0x4b004b4b,0xb700b7b7,0xa500a5a5, + 0x89008989,0x5f005f5f,0xb100b1b1,0x17001717, + 0xf400f4f4,0xbc00bcbc,0xd300d3d3,0x46004646, + 0xcf00cfcf,0x37003737,0x5e005e5e,0x47004747, + 0x94009494,0xfa00fafa,0xfc00fcfc,0x5b005b5b, + 0x97009797,0xfe00fefe,0x5a005a5a,0xac00acac, + 0x3c003c3c,0x4c004c4c,0x03000303,0x35003535, + 0xf300f3f3,0x23002323,0xb800b8b8,0x5d005d5d, + 0x6a006a6a,0x92009292,0xd500d5d5,0x21002121, + 0x44004444,0x51005151,0xc600c6c6,0x7d007d7d, + 0x39003939,0x83008383,0xdc00dcdc,0xaa00aaaa, + 0x7c007c7c,0x77007777,0x56005656,0x05000505, + 0x1b001b1b,0xa400a4a4,0x15001515,0x34003434, + 0x1e001e1e,0x1c001c1c,0xf800f8f8,0x52005252, + 0x20002020,0x14001414,0xe900e9e9,0xbd00bdbd, + 0xdd00dddd,0xe400e4e4,0xa100a1a1,0xe000e0e0, + 0x8a008a8a,0xf100f1f1,0xd600d6d6,0x7a007a7a, + 0xbb00bbbb,0xe300e3e3,0x40004040,0x4f004f4f, +}; + +static const u32 camellia_sp4404[256] = { + 0x70700070,0x2c2c002c,0xb3b300b3,0xc0c000c0, + 0xe4e400e4,0x57570057,0xeaea00ea,0xaeae00ae, + 0x23230023,0x6b6b006b,0x45450045,0xa5a500a5, + 0xeded00ed,0x4f4f004f,0x1d1d001d,0x92920092, + 0x86860086,0xafaf00af,0x7c7c007c,0x1f1f001f, + 0x3e3e003e,0xdcdc00dc,0x5e5e005e,0x0b0b000b, + 0xa6a600a6,0x39390039,0xd5d500d5,0x5d5d005d, + 0xd9d900d9,0x5a5a005a,0x51510051,0x6c6c006c, + 0x8b8b008b,0x9a9a009a,0xfbfb00fb,0xb0b000b0, + 0x74740074,0x2b2b002b,0xf0f000f0,0x84840084, + 0xdfdf00df,0xcbcb00cb,0x34340034,0x76760076, + 0x6d6d006d,0xa9a900a9,0xd1d100d1,0x04040004, + 0x14140014,0x3a3a003a,0xdede00de,0x11110011, + 0x32320032,0x9c9c009c,0x53530053,0xf2f200f2, + 0xfefe00fe,0xcfcf00cf,0xc3c300c3,0x7a7a007a, + 0x24240024,0xe8e800e8,0x60600060,0x69690069, + 0xaaaa00aa,0xa0a000a0,0xa1a100a1,0x62620062, + 0x54540054,0x1e1e001e,0xe0e000e0,0x64640064, + 0x10100010,0x00000000,0xa3a300a3,0x75750075, + 0x8a8a008a,0xe6e600e6,0x09090009,0xdddd00dd, + 0x87870087,0x83830083,0xcdcd00cd,0x90900090, + 0x73730073,0xf6f600f6,0x9d9d009d,0xbfbf00bf, + 0x52520052,0xd8d800d8,0xc8c800c8,0xc6c600c6, + 0x81810081,0x6f6f006f,0x13130013,0x63630063, + 0xe9e900e9,0xa7a700a7,0x9f9f009f,0xbcbc00bc, + 0x29290029,0xf9f900f9,0x2f2f002f,0xb4b400b4, + 0x78780078,0x06060006,0xe7e700e7,0x71710071, + 0xd4d400d4,0xabab00ab,0x88880088,0x8d8d008d, + 0x72720072,0xb9b900b9,0xf8f800f8,0xacac00ac, + 0x36360036,0x2a2a002a,0x3c3c003c,0xf1f100f1, + 0x40400040,0xd3d300d3,0xbbbb00bb,0x43430043, + 0x15150015,0xadad00ad,0x77770077,0x80800080, + 0x82820082,0xecec00ec,0x27270027,0xe5e500e5, + 0x85850085,0x35350035,0x0c0c000c,0x41410041, + 0xefef00ef,0x93930093,0x19190019,0x21210021, + 0x0e0e000e,0x4e4e004e,0x65650065,0xbdbd00bd, + 0xb8b800b8,0x8f8f008f,0xebeb00eb,0xcece00ce, + 0x30300030,0x5f5f005f,0xc5c500c5,0x1a1a001a, + 0xe1e100e1,0xcaca00ca,0x47470047,0x3d3d003d, + 0x01010001,0xd6d600d6,0x56560056,0x4d4d004d, + 0x0d0d000d,0x66660066,0xcccc00cc,0x2d2d002d, + 0x12120012,0x20200020,0xb1b100b1,0x99990099, + 0x4c4c004c,0xc2c200c2,0x7e7e007e,0x05050005, + 0xb7b700b7,0x31310031,0x17170017,0xd7d700d7, + 0x58580058,0x61610061,0x1b1b001b,0x1c1c001c, + 0x0f0f000f,0x16160016,0x18180018,0x22220022, + 0x44440044,0xb2b200b2,0xb5b500b5,0x91910091, + 0x08080008,0xa8a800a8,0xfcfc00fc,0x50500050, + 0xd0d000d0,0x7d7d007d,0x89890089,0x97970097, + 0x5b5b005b,0x95950095,0xffff00ff,0xd2d200d2, + 0xc4c400c4,0x48480048,0xf7f700f7,0xdbdb00db, + 0x03030003,0xdada00da,0x3f3f003f,0x94940094, + 0x5c5c005c,0x02020002,0x4a4a004a,0x33330033, + 0x67670067,0xf3f300f3,0x7f7f007f,0xe2e200e2, + 0x9b9b009b,0x26260026,0x37370037,0x3b3b003b, + 0x96960096,0x4b4b004b,0xbebe00be,0x2e2e002e, + 0x79790079,0x8c8c008c,0x6e6e006e,0x8e8e008e, + 0xf5f500f5,0xb6b600b6,0xfdfd00fd,0x59590059, + 0x98980098,0x6a6a006a,0x46460046,0xbaba00ba, + 0x25250025,0x42420042,0xa2a200a2,0xfafa00fa, + 0x07070007,0x55550055,0xeeee00ee,0x0a0a000a, + 0x49490049,0x68680068,0x38380038,0xa4a400a4, + 0x28280028,0x7b7b007b,0xc9c900c9,0xc1c100c1, + 0xe3e300e3,0xf4f400f4,0xc7c700c7,0x9e9e009e, +}; + + + +static void camellia_setup128(const unsigned char *key, u32 *subkey) +{ + u32 kll, klr, krl, krr; + u32 il, ir, t0, t1, w0, w1; + u32 kw4l, kw4r, dw, tl, tr; + u32 subL[26]; + u32 subR[26]; + + /** + * k == kll || klr || krl || krr (|| is concatination) + */ + kll = GETU32(key ); + klr = GETU32(key + 4); + krl = GETU32(key + 8); + krr = GETU32(key + 12); + /** + * generate KL dependent subkeys + */ + /* kw1 */ + SUBL(0) = kll; SUBR(0) = klr; + /* kw2 */ + SUBL(1) = krl; SUBR(1) = krr; + /* rotation left shift 15bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k3 */ + SUBL(4) = kll; SUBR(4) = klr; + /* k4 */ + SUBL(5) = krl; SUBR(5) = krr; + /* rotation left shift 15+30bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + /* k7 */ + SUBL(10) = kll; SUBR(10) = klr; + /* k8 */ + SUBL(11) = krl; SUBR(11) = krr; + /* rotation left shift 15+30+15bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k10 */ + SUBL(13) = krl; SUBR(13) = krr; + /* rotation left shift 15+30+15+17 bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* kl3 */ + SUBL(16) = kll; SUBR(16) = klr; + /* kl4 */ + SUBL(17) = krl; SUBR(17) = krr; + /* rotation left shift 15+30+15+17+17 bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* k13 */ + SUBL(18) = kll; SUBR(18) = klr; + /* k14 */ + SUBL(19) = krl; SUBR(19) = krr; + /* rotation left shift 15+30+15+17+17+17 bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* k17 */ + SUBL(22) = kll; SUBR(22) = klr; + /* k18 */ + SUBL(23) = krl; SUBR(23) = krr; + + /* generate KA */ + kll = SUBL(0); klr = SUBR(0); + krl = SUBL(1); krr = SUBR(1); + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, + w0, w1, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, + kll, klr, il, ir, t0, t1); + /* current status == (kll, klr, w0, w1) */ + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, + krl, krr, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, + w0, w1, il, ir, t0, t1); + kll ^= w0; klr ^= w1; + + /* generate KA dependent subkeys */ + /* k1, k2 */ + SUBL(2) = kll; SUBR(2) = klr; + SUBL(3) = krl; SUBR(3) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k5,k6 */ + SUBL(6) = kll; SUBR(6) = klr; + SUBL(7) = krl; SUBR(7) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* kl1, kl2 */ + SUBL(8) = kll; SUBR(8) = klr; + SUBL(9) = krl; SUBR(9) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k9 */ + SUBL(12) = kll; SUBR(12) = klr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k11, k12 */ + SUBL(14) = kll; SUBR(14) = klr; + SUBL(15) = krl; SUBR(15) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + /* k15, k16 */ + SUBL(20) = kll; SUBR(20) = klr; + SUBL(21) = krl; SUBR(21) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* kw3, kw4 */ + SUBL(24) = kll; SUBR(24) = klr; + SUBL(25) = krl; SUBR(25) = krr; + + + /* absorb kw2 to other subkeys */ + /* round 2 */ + SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1); + /* round 4 */ + SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1); + /* round 6 */ + SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(9); + dw = SUBL(1) & SUBL(9), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */ + /* round 8 */ + SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1); + /* round 10 */ + SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1); + /* round 12 */ + SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(17); + dw = SUBL(1) & SUBL(17), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */ + /* round 14 */ + SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1); + /* round 16 */ + SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1); + /* round 18 */ + SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1); + /* kw3 */ + SUBL(24) ^= SUBL(1); SUBR(24) ^= SUBR(1); + + /* absorb kw4 to other subkeys */ + kw4l = SUBL(25); kw4r = SUBR(25); + /* round 17 */ + SUBL(22) ^= kw4l; SUBR(22) ^= kw4r; + /* round 15 */ + SUBL(20) ^= kw4l; SUBR(20) ^= kw4r; + /* round 13 */ + SUBL(18) ^= kw4l; SUBR(18) ^= kw4r; + kw4l ^= kw4r & ~SUBR(16); + dw = kw4l & SUBL(16), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */ + /* round 11 */ + SUBL(14) ^= kw4l; SUBR(14) ^= kw4r; + /* round 9 */ + SUBL(12) ^= kw4l; SUBR(12) ^= kw4r; + /* round 7 */ + SUBL(10) ^= kw4l; SUBR(10) ^= kw4r; + kw4l ^= kw4r & ~SUBR(8); + dw = kw4l & SUBL(8), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */ + /* round 5 */ + SUBL(6) ^= kw4l; SUBR(6) ^= kw4r; + /* round 3 */ + SUBL(4) ^= kw4l; SUBR(4) ^= kw4r; + /* round 1 */ + SUBL(2) ^= kw4l; SUBR(2) ^= kw4r; + /* kw1 */ + SUBL(0) ^= kw4l; SUBR(0) ^= kw4r; + + + /* key XOR is end of F-function */ + CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */ + CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2); + CAMELLIA_SUBKEY_L(2) = SUBL(3); /* round 1 */ + CAMELLIA_SUBKEY_R(2) = SUBR(3); + CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */ + CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4); + CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */ + CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5); + CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */ + CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6); + CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */ + CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7); + tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8)); + dw = tl & SUBL(8), /* FL(kl1) */ + tr = SUBR(10) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */ + CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr; + CAMELLIA_SUBKEY_L(8) = SUBL(8); /* FL(kl1) */ + CAMELLIA_SUBKEY_R(8) = SUBR(8); + CAMELLIA_SUBKEY_L(9) = SUBL(9); /* FLinv(kl2) */ + CAMELLIA_SUBKEY_R(9) = SUBR(9); + tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9)); + dw = tl & SUBL(9), /* FLinv(kl2) */ + tr = SUBR(7) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */ + CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11); + CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */ + CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12); + CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */ + CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13); + CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */ + CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14); + CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */ + CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15); + tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16)); + dw = tl & SUBL(16), /* FL(kl3) */ + tr = SUBR(18) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */ + CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr; + CAMELLIA_SUBKEY_L(16) = SUBL(16); /* FL(kl3) */ + CAMELLIA_SUBKEY_R(16) = SUBR(16); + CAMELLIA_SUBKEY_L(17) = SUBL(17); /* FLinv(kl4) */ + CAMELLIA_SUBKEY_R(17) = SUBR(17); + tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17)); + dw = tl & SUBL(17), /* FLinv(kl4) */ + tr = SUBR(15) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */ + CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19); + CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */ + CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20); + CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */ + CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21); + CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */ + CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22); + CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */ + CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23); + CAMELLIA_SUBKEY_L(23) = SUBL(22); /* round 18 */ + CAMELLIA_SUBKEY_R(23) = SUBR(22); + CAMELLIA_SUBKEY_L(24) = SUBL(24) ^ SUBL(23); /* kw3 */ + CAMELLIA_SUBKEY_R(24) = SUBR(24) ^ SUBR(23); + + /* apply the inverse of the last half of P-function */ + dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2), + dw = CAMELLIA_RL8(dw);/* round 1 */ + CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw, + CAMELLIA_SUBKEY_L(2) = dw; + dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3), + dw = CAMELLIA_RL8(dw);/* round 2 */ + CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw, + CAMELLIA_SUBKEY_L(3) = dw; + dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4), + dw = CAMELLIA_RL8(dw);/* round 3 */ + CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw, + CAMELLIA_SUBKEY_L(4) = dw; + dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5), + dw = CAMELLIA_RL8(dw);/* round 4 */ + CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw, + CAMELLIA_SUBKEY_L(5) = dw; + dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6), + dw = CAMELLIA_RL8(dw);/* round 5 */ + CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw, + CAMELLIA_SUBKEY_L(6) = dw; + dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7), + dw = CAMELLIA_RL8(dw);/* round 6 */ + CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw, + CAMELLIA_SUBKEY_L(7) = dw; + dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10), + dw = CAMELLIA_RL8(dw);/* round 7 */ + CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw, + CAMELLIA_SUBKEY_L(10) = dw; + dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11), + dw = CAMELLIA_RL8(dw);/* round 8 */ + CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw, + CAMELLIA_SUBKEY_L(11) = dw; + dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12), + dw = CAMELLIA_RL8(dw);/* round 9 */ + CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw, + CAMELLIA_SUBKEY_L(12) = dw; + dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13), + dw = CAMELLIA_RL8(dw);/* round 10 */ + CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw, + CAMELLIA_SUBKEY_L(13) = dw; + dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14), + dw = CAMELLIA_RL8(dw);/* round 11 */ + CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw, + CAMELLIA_SUBKEY_L(14) = dw; + dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15), + dw = CAMELLIA_RL8(dw);/* round 12 */ + CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw, + CAMELLIA_SUBKEY_L(15) = dw; + dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18), + dw = CAMELLIA_RL8(dw);/* round 13 */ + CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw, + CAMELLIA_SUBKEY_L(18) = dw; + dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19), + dw = CAMELLIA_RL8(dw);/* round 14 */ + CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw, + CAMELLIA_SUBKEY_L(19) = dw; + dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20), + dw = CAMELLIA_RL8(dw);/* round 15 */ + CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw, + CAMELLIA_SUBKEY_L(20) = dw; + dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21), + dw = CAMELLIA_RL8(dw);/* round 16 */ + CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw, + CAMELLIA_SUBKEY_L(21) = dw; + dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22), + dw = CAMELLIA_RL8(dw);/* round 17 */ + CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw, + CAMELLIA_SUBKEY_L(22) = dw; + dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23), + dw = CAMELLIA_RL8(dw);/* round 18 */ + CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw, + CAMELLIA_SUBKEY_L(23) = dw; + + return; +} + + +static void camellia_setup256(const unsigned char *key, u32 *subkey) +{ + u32 kll,klr,krl,krr; /* left half of key */ + u32 krll,krlr,krrl,krrr; /* right half of key */ + u32 il, ir, t0, t1, w0, w1; /* temporary variables */ + u32 kw4l, kw4r, dw, tl, tr; + u32 subL[34]; + u32 subR[34]; + + /** + * key = (kll || klr || krl || krr || krll || krlr || krrl || krrr) + * (|| is concatination) + */ + + kll = GETU32(key ); + klr = GETU32(key + 4); + krl = GETU32(key + 8); + krr = GETU32(key + 12); + krll = GETU32(key + 16); + krlr = GETU32(key + 20); + krrl = GETU32(key + 24); + krrr = GETU32(key + 28); + + /* generate KL dependent subkeys */ + /* kw1 */ + SUBL(0) = kll; SUBR(0) = klr; + /* kw2 */ + SUBL(1) = krl; SUBR(1) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45); + /* k9 */ + SUBL(12) = kll; SUBR(12) = klr; + /* k10 */ + SUBL(13) = krl; SUBR(13) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* kl3 */ + SUBL(16) = kll; SUBR(16) = klr; + /* kl4 */ + SUBL(17) = krl; SUBR(17) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* k17 */ + SUBL(22) = kll; SUBR(22) = klr; + /* k18 */ + SUBL(23) = krl; SUBR(23) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + /* k23 */ + SUBL(30) = kll; SUBR(30) = klr; + /* k24 */ + SUBL(31) = krl; SUBR(31) = krr; + + /* generate KR dependent subkeys */ + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + /* k3 */ + SUBL(4) = krll; SUBR(4) = krlr; + /* k4 */ + SUBL(5) = krrl; SUBR(5) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + /* kl1 */ + SUBL(8) = krll; SUBR(8) = krlr; + /* kl2 */ + SUBL(9) = krrl; SUBR(9) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + /* k13 */ + SUBL(18) = krll; SUBR(18) = krlr; + /* k14 */ + SUBL(19) = krrl; SUBR(19) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + /* k19 */ + SUBL(26) = krll; SUBR(26) = krlr; + /* k20 */ + SUBL(27) = krrl; SUBR(27) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + + /* generate KA */ + kll = SUBL(0) ^ krll; klr = SUBR(0) ^ krlr; + krl = SUBL(1) ^ krrl; krr = SUBR(1) ^ krrr; + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, + w0, w1, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, + kll, klr, il, ir, t0, t1); + kll ^= krll; klr ^= krlr; + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, + krl, krr, il, ir, t0, t1); + krl ^= w0 ^ krrl; krr ^= w1 ^ krrr; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, + w0, w1, il, ir, t0, t1); + kll ^= w0; klr ^= w1; + + /* generate KB */ + krll ^= kll; krlr ^= klr; + krrl ^= krl; krrr ^= krr; + CAMELLIA_F(krll, krlr, + CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R, + w0, w1, il, ir, t0, t1); + krrl ^= w0; krrr ^= w1; + CAMELLIA_F(krrl, krrr, + CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R, + w0, w1, il, ir, t0, t1); + krll ^= w0; krlr ^= w1; + + /* generate KA dependent subkeys */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k5 */ + SUBL(6) = kll; SUBR(6) = klr; + /* k6 */ + SUBL(7) = krl; SUBR(7) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + /* k11 */ + SUBL(14) = kll; SUBR(14) = klr; + /* k12 */ + SUBL(15) = krl; SUBR(15) = krr; + /* rotation left shift 32bit */ + /* kl5 */ + SUBL(24) = klr; SUBR(24) = krl; + /* kl6 */ + SUBL(25) = krr; SUBR(25) = kll; + /* rotation left shift 49 from k11,k12 -> k21,k22 */ + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49); + /* k21 */ + SUBL(28) = kll; SUBR(28) = klr; + /* k22 */ + SUBL(29) = krl; SUBR(29) = krr; + + /* generate KB dependent subkeys */ + /* k1 */ + SUBL(2) = krll; SUBR(2) = krlr; + /* k2 */ + SUBL(3) = krrl; SUBR(3) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + /* k7 */ + SUBL(10) = krll; SUBR(10) = krlr; + /* k8 */ + SUBL(11) = krrl; SUBR(11) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + /* k15 */ + SUBL(20) = krll; SUBR(20) = krlr; + /* k16 */ + SUBL(21) = krrl; SUBR(21) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51); + /* kw3 */ + SUBL(32) = krll; SUBR(32) = krlr; + /* kw4 */ + SUBL(33) = krrl; SUBR(33) = krrr; + + /* absorb kw2 to other subkeys */ + /* round 2 */ + SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1); + /* round 4 */ + SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1); + /* round 6 */ + SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(9); + dw = SUBL(1) & SUBL(9), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */ + /* round 8 */ + SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1); + /* round 10 */ + SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1); + /* round 12 */ + SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(17); + dw = SUBL(1) & SUBL(17), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */ + /* round 14 */ + SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1); + /* round 16 */ + SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1); + /* round 18 */ + SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(25); + dw = SUBL(1) & SUBL(25), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl6) */ + /* round 20 */ + SUBL(27) ^= SUBL(1); SUBR(27) ^= SUBR(1); + /* round 22 */ + SUBL(29) ^= SUBL(1); SUBR(29) ^= SUBR(1); + /* round 24 */ + SUBL(31) ^= SUBL(1); SUBR(31) ^= SUBR(1); + /* kw3 */ + SUBL(32) ^= SUBL(1); SUBR(32) ^= SUBR(1); + + + /* absorb kw4 to other subkeys */ + kw4l = SUBL(33); kw4r = SUBR(33); + /* round 23 */ + SUBL(30) ^= kw4l; SUBR(30) ^= kw4r; + /* round 21 */ + SUBL(28) ^= kw4l; SUBR(28) ^= kw4r; + /* round 19 */ + SUBL(26) ^= kw4l; SUBR(26) ^= kw4r; + kw4l ^= kw4r & ~SUBR(24); + dw = kw4l & SUBL(24), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl5) */ + /* round 17 */ + SUBL(22) ^= kw4l; SUBR(22) ^= kw4r; + /* round 15 */ + SUBL(20) ^= kw4l; SUBR(20) ^= kw4r; + /* round 13 */ + SUBL(18) ^= kw4l; SUBR(18) ^= kw4r; + kw4l ^= kw4r & ~SUBR(16); + dw = kw4l & SUBL(16), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */ + /* round 11 */ + SUBL(14) ^= kw4l; SUBR(14) ^= kw4r; + /* round 9 */ + SUBL(12) ^= kw4l; SUBR(12) ^= kw4r; + /* round 7 */ + SUBL(10) ^= kw4l; SUBR(10) ^= kw4r; + kw4l ^= kw4r & ~SUBR(8); + dw = kw4l & SUBL(8), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */ + /* round 5 */ + SUBL(6) ^= kw4l; SUBR(6) ^= kw4r; + /* round 3 */ + SUBL(4) ^= kw4l; SUBR(4) ^= kw4r; + /* round 1 */ + SUBL(2) ^= kw4l; SUBR(2) ^= kw4r; + /* kw1 */ + SUBL(0) ^= kw4l; SUBR(0) ^= kw4r; + + /* key XOR is end of F-function */ + CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */ + CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2); + CAMELLIA_SUBKEY_L(2) = SUBL(3); /* round 1 */ + CAMELLIA_SUBKEY_R(2) = SUBR(3); + CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */ + CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4); + CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */ + CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5); + CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */ + CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6); + CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */ + CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7); + tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8)); + dw = tl & SUBL(8), /* FL(kl1) */ + tr = SUBR(10) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */ + CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr; + CAMELLIA_SUBKEY_L(8) = SUBL(8); /* FL(kl1) */ + CAMELLIA_SUBKEY_R(8) = SUBR(8); + CAMELLIA_SUBKEY_L(9) = SUBL(9); /* FLinv(kl2) */ + CAMELLIA_SUBKEY_R(9) = SUBR(9); + tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9)); + dw = tl & SUBL(9), /* FLinv(kl2) */ + tr = SUBR(7) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */ + CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11); + CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */ + CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12); + CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */ + CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13); + CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */ + CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14); + CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */ + CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15); + tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16)); + dw = tl & SUBL(16), /* FL(kl3) */ + tr = SUBR(18) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */ + CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr; + CAMELLIA_SUBKEY_L(16) = SUBL(16); /* FL(kl3) */ + CAMELLIA_SUBKEY_R(16) = SUBR(16); + CAMELLIA_SUBKEY_L(17) = SUBL(17); /* FLinv(kl4) */ + CAMELLIA_SUBKEY_R(17) = SUBR(17); + tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17)); + dw = tl & SUBL(17), /* FLinv(kl4) */ + tr = SUBR(15) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */ + CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19); + CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */ + CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20); + CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */ + CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21); + CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */ + CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22); + CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */ + CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23); + tl = SUBL(26) ^ (SUBR(26) + & ~SUBR(24)); + dw = tl & SUBL(24), /* FL(kl5) */ + tr = SUBR(26) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(23) = SUBL(22) ^ tl; /* round 18 */ + CAMELLIA_SUBKEY_R(23) = SUBR(22) ^ tr; + CAMELLIA_SUBKEY_L(24) = SUBL(24); /* FL(kl5) */ + CAMELLIA_SUBKEY_R(24) = SUBR(24); + CAMELLIA_SUBKEY_L(25) = SUBL(25); /* FLinv(kl6) */ + CAMELLIA_SUBKEY_R(25) = SUBR(25); + tl = SUBL(23) ^ (SUBR(23) & + ~SUBR(25)); + dw = tl & SUBL(25), /* FLinv(kl6) */ + tr = SUBR(23) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(26) = tl ^ SUBL(27); /* round 19 */ + CAMELLIA_SUBKEY_R(26) = tr ^ SUBR(27); + CAMELLIA_SUBKEY_L(27) = SUBL(26) ^ SUBL(28); /* round 20 */ + CAMELLIA_SUBKEY_R(27) = SUBR(26) ^ SUBR(28); + CAMELLIA_SUBKEY_L(28) = SUBL(27) ^ SUBL(29); /* round 21 */ + CAMELLIA_SUBKEY_R(28) = SUBR(27) ^ SUBR(29); + CAMELLIA_SUBKEY_L(29) = SUBL(28) ^ SUBL(30); /* round 22 */ + CAMELLIA_SUBKEY_R(29) = SUBR(28) ^ SUBR(30); + CAMELLIA_SUBKEY_L(30) = SUBL(29) ^ SUBL(31); /* round 23 */ + CAMELLIA_SUBKEY_R(30) = SUBR(29) ^ SUBR(31); + CAMELLIA_SUBKEY_L(31) = SUBL(30); /* round 24 */ + CAMELLIA_SUBKEY_R(31) = SUBR(30); + CAMELLIA_SUBKEY_L(32) = SUBL(32) ^ SUBL(31); /* kw3 */ + CAMELLIA_SUBKEY_R(32) = SUBR(32) ^ SUBR(31); + + /* apply the inverse of the last half of P-function */ + dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2), + dw = CAMELLIA_RL8(dw);/* round 1 */ + CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw, + CAMELLIA_SUBKEY_L(2) = dw; + dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3), + dw = CAMELLIA_RL8(dw);/* round 2 */ + CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw, + CAMELLIA_SUBKEY_L(3) = dw; + dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4), + dw = CAMELLIA_RL8(dw);/* round 3 */ + CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw, + CAMELLIA_SUBKEY_L(4) = dw; + dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5), + dw = CAMELLIA_RL8(dw);/* round 4 */ + CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw, + CAMELLIA_SUBKEY_L(5) = dw; + dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6), + dw = CAMELLIA_RL8(dw);/* round 5 */ + CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw, + CAMELLIA_SUBKEY_L(6) = dw; + dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7), + dw = CAMELLIA_RL8(dw);/* round 6 */ + CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw, + CAMELLIA_SUBKEY_L(7) = dw; + dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10), + dw = CAMELLIA_RL8(dw);/* round 7 */ + CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw, + CAMELLIA_SUBKEY_L(10) = dw; + dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11), + dw = CAMELLIA_RL8(dw);/* round 8 */ + CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw, + CAMELLIA_SUBKEY_L(11) = dw; + dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12), + dw = CAMELLIA_RL8(dw);/* round 9 */ + CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw, + CAMELLIA_SUBKEY_L(12) = dw; + dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13), + dw = CAMELLIA_RL8(dw);/* round 10 */ + CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw, + CAMELLIA_SUBKEY_L(13) = dw; + dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14), + dw = CAMELLIA_RL8(dw);/* round 11 */ + CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw, + CAMELLIA_SUBKEY_L(14) = dw; + dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15), + dw = CAMELLIA_RL8(dw);/* round 12 */ + CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw, + CAMELLIA_SUBKEY_L(15) = dw; + dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18), + dw = CAMELLIA_RL8(dw);/* round 13 */ + CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw, + CAMELLIA_SUBKEY_L(18) = dw; + dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19), + dw = CAMELLIA_RL8(dw);/* round 14 */ + CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw, + CAMELLIA_SUBKEY_L(19) = dw; + dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20), + dw = CAMELLIA_RL8(dw);/* round 15 */ + CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw, + CAMELLIA_SUBKEY_L(20) = dw; + dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21), + dw = CAMELLIA_RL8(dw);/* round 16 */ + CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw, + CAMELLIA_SUBKEY_L(21) = dw; + dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22), + dw = CAMELLIA_RL8(dw);/* round 17 */ + CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw, + CAMELLIA_SUBKEY_L(22) = dw; + dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23), + dw = CAMELLIA_RL8(dw);/* round 18 */ + CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw, + CAMELLIA_SUBKEY_L(23) = dw; + dw = CAMELLIA_SUBKEY_L(26) ^ CAMELLIA_SUBKEY_R(26), + dw = CAMELLIA_RL8(dw);/* round 19 */ + CAMELLIA_SUBKEY_R(26) = CAMELLIA_SUBKEY_L(26) ^ dw, + CAMELLIA_SUBKEY_L(26) = dw; + dw = CAMELLIA_SUBKEY_L(27) ^ CAMELLIA_SUBKEY_R(27), + dw = CAMELLIA_RL8(dw);/* round 20 */ + CAMELLIA_SUBKEY_R(27) = CAMELLIA_SUBKEY_L(27) ^ dw, + CAMELLIA_SUBKEY_L(27) = dw; + dw = CAMELLIA_SUBKEY_L(28) ^ CAMELLIA_SUBKEY_R(28), + dw = CAMELLIA_RL8(dw);/* round 21 */ + CAMELLIA_SUBKEY_R(28) = CAMELLIA_SUBKEY_L(28) ^ dw, + CAMELLIA_SUBKEY_L(28) = dw; + dw = CAMELLIA_SUBKEY_L(29) ^ CAMELLIA_SUBKEY_R(29), + dw = CAMELLIA_RL8(dw);/* round 22 */ + CAMELLIA_SUBKEY_R(29) = CAMELLIA_SUBKEY_L(29) ^ dw, + CAMELLIA_SUBKEY_L(29) = dw; + dw = CAMELLIA_SUBKEY_L(30) ^ CAMELLIA_SUBKEY_R(30), + dw = CAMELLIA_RL8(dw);/* round 23 */ + CAMELLIA_SUBKEY_R(30) = CAMELLIA_SUBKEY_L(30) ^ dw, + CAMELLIA_SUBKEY_L(30) = dw; + dw = CAMELLIA_SUBKEY_L(31) ^ CAMELLIA_SUBKEY_R(31), + dw = CAMELLIA_RL8(dw);/* round 24 */ + CAMELLIA_SUBKEY_R(31) = CAMELLIA_SUBKEY_L(31) ^ dw, + CAMELLIA_SUBKEY_L(31) = dw; + + return; +} + +static void camellia_setup192(const unsigned char *key, u32 *subkey) +{ + unsigned char kk[32]; + u32 krll, krlr, krrl,krrr; + + memcpy(kk, key, 24); + memcpy((unsigned char *)&krll, key+16,4); + memcpy((unsigned char *)&krlr, key+20,4); + krrl = ~krll; + krrr = ~krlr; + memcpy(kk+24, (unsigned char *)&krrl, 4); + memcpy(kk+28, (unsigned char *)&krrr, 4); + camellia_setup256(kk, subkey); + return; +} + + +/** + * Stuff related to camellia encryption/decryption + */ +static void camellia_encrypt128(const u32 *subkey, __be32 *io_text) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + u32 io[4]; + + io[0] = be32_to_cpu(io_text[0]); + io[1] = be32_to_cpu(io_text[1]); + io[2] = be32_to_cpu(io_text[2]); + io[3] = be32_to_cpu(io_text[3]); + + /* pre whitening but absorb kw2*/ + io[0] ^= CAMELLIA_SUBKEY_L(0); + io[1] ^= CAMELLIA_SUBKEY_R(0); + /* main iteration */ + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), + CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), + CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CAMELLIA_SUBKEY_L(24); + io[3] ^= CAMELLIA_SUBKEY_R(24); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + io_text[0] = cpu_to_be32(io[0]); + io_text[1] = cpu_to_be32(io[1]); + io_text[2] = cpu_to_be32(io[2]); + io_text[3] = cpu_to_be32(io[3]); + + return; +} + +static void camellia_decrypt128(const u32 *subkey, __be32 *io_text) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + u32 io[4]; + + io[0] = be32_to_cpu(io_text[0]); + io[1] = be32_to_cpu(io_text[1]); + io[2] = be32_to_cpu(io_text[2]); + io[3] = be32_to_cpu(io_text[3]); + + /* pre whitening but absorb kw2*/ + io[0] ^= CAMELLIA_SUBKEY_L(24); + io[1] ^= CAMELLIA_SUBKEY_R(24); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), + CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), + CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CAMELLIA_SUBKEY_L(0); + io[3] ^= CAMELLIA_SUBKEY_R(0); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + io_text[0] = cpu_to_be32(io[0]); + io_text[1] = cpu_to_be32(io[1]); + io_text[2] = cpu_to_be32(io[2]); + io_text[3] = cpu_to_be32(io[3]); + + return; +} + + +/** + * stuff for 192 and 256bit encryption/decryption + */ +static void camellia_encrypt256(const u32 *subkey, __be32 *io_text) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + u32 io[4]; + + io[0] = be32_to_cpu(io_text[0]); + io[1] = be32_to_cpu(io_text[1]); + io[2] = be32_to_cpu(io_text[2]); + io[3] = be32_to_cpu(io_text[3]); + + /* pre whitening but absorb kw2*/ + io[0] ^= CAMELLIA_SUBKEY_L(0); + io[1] ^= CAMELLIA_SUBKEY_R(0); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), + CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), + CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24), + CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CAMELLIA_SUBKEY_L(32); + io[3] ^= CAMELLIA_SUBKEY_R(32); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + io_text[0] = cpu_to_be32(io[0]); + io_text[1] = cpu_to_be32(io[1]); + io_text[2] = cpu_to_be32(io[2]); + io_text[3] = cpu_to_be32(io[3]); + + return; +} + + +static void camellia_decrypt256(const u32 *subkey, __be32 *io_text) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + u32 io[4]; + + io[0] = be32_to_cpu(io_text[0]); + io[1] = be32_to_cpu(io_text[1]); + io[2] = be32_to_cpu(io_text[2]); + io[3] = be32_to_cpu(io_text[3]); + + /* pre whitening but absorb kw2*/ + io[0] ^= CAMELLIA_SUBKEY_L(32); + io[1] ^= CAMELLIA_SUBKEY_R(32); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25), + CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), + CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), + CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CAMELLIA_SUBKEY_L(0); + io[3] ^= CAMELLIA_SUBKEY_R(0); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + io_text[0] = cpu_to_be32(io[0]); + io_text[1] = cpu_to_be32(io[1]); + io_text[2] = cpu_to_be32(io[2]); + io_text[3] = cpu_to_be32(io[3]); + + return; +} + + +static int +camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); + const unsigned char *key = (const unsigned char *)in_key; + u32 *flags = &tfm->crt_flags; + + if (key_len != 16 && key_len != 24 && key_len != 32) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + cctx->key_length = key_len; + + switch(key_len) { + case 16: + camellia_setup128(key, cctx->key_table); + break; + case 24: + camellia_setup192(key, cctx->key_table); + break; + case 32: + camellia_setup256(key, cctx->key_table); + break; + default: + break; + } + + return 0; +} + + +static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); + const __be32 *src = (const __be32 *)in; + __be32 *dst = (__be32 *)out; + + __be32 tmp[4]; + + memcpy(tmp, src, CAMELLIA_BLOCK_SIZE); + + switch (cctx->key_length) { + case 16: + camellia_encrypt128(cctx->key_table, tmp); + break; + case 24: + /* fall through */ + case 32: + camellia_encrypt256(cctx->key_table, tmp); + break; + default: + break; + } + + memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE); +} + + +static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); + const __be32 *src = (const __be32 *)in; + __be32 *dst = (__be32 *)out; + + __be32 tmp[4]; + + memcpy(tmp, src, CAMELLIA_BLOCK_SIZE); + + switch (cctx->key_length) { + case 16: + camellia_decrypt128(cctx->key_table, tmp); + break; + case 24: + /* fall through */ + case 32: + camellia_decrypt256(cctx->key_table, tmp); + break; + default: + break; + } + + memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE); +} + + +static struct crypto_alg camellia_alg = { + .cra_name = "camellia", + .cra_driver_name = "camellia-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, + .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE, + .cia_setkey = camellia_set_key, + .cia_encrypt = camellia_encrypt, + .cia_decrypt = camellia_decrypt + } + } +}; + +static int __init camellia_init(void) +{ + return crypto_register_alg(&camellia_alg); +} + + +static void __exit camellia_fini(void) +{ + crypto_unregister_alg(&camellia_alg); +} + + +module_init(camellia_init); +module_exit(camellia_fini); + + +MODULE_DESCRIPTION("Camellia Cipher Algorithm"); +MODULE_LICENSE("GPL"); diff --git a/trunk/crypto/cbc.c b/trunk/crypto/cbc.c index f5542b4db387..136fea7e7000 100644 --- a/trunk/crypto/cbc.c +++ b/trunk/crypto/cbc.c @@ -243,6 +243,7 @@ static int crypto_cbc_init_tfm(struct crypto_tfm *tfm) struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; switch (crypto_tfm_alg_blocksize(tfm)) { case 8: @@ -260,11 +261,11 @@ static int crypto_cbc_init_tfm(struct crypto_tfm *tfm) ctx->xor = xor_quad; } - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); - ctx->child = crypto_cipher_cast(tfm); + ctx->child = cipher; return 0; } diff --git a/trunk/crypto/cipher.c b/trunk/crypto/cipher.c index 9e03701cfdcc..333aab2f0277 100644 --- a/trunk/crypto/cipher.c +++ b/trunk/crypto/cipher.c @@ -12,274 +12,13 @@ * any later version. * */ -#include + #include #include #include -#include -#include +#include #include -#include #include "internal.h" -#include "scatterwalk.h" - -struct cipher_alg_compat { - unsigned int cia_min_keysize; - unsigned int cia_max_keysize; - int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen); - void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - - unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); - unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); - unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); - unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); -}; - -static inline void xor_64(u8 *a, const u8 *b) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; -} - -static inline void xor_128(u8 *a, const u8 *b) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; - ((u32 *)a)[2] ^= ((u32 *)b)[2]; - ((u32 *)a)[3] ^= ((u32 *)b)[3]; -} - -static unsigned int crypt_slow(const struct cipher_desc *desc, - struct scatter_walk *in, - struct scatter_walk *out, unsigned int bsize) -{ - unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm); - u8 buffer[bsize * 2 + alignmask]; - u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - u8 *dst = src + bsize; - - scatterwalk_copychunks(src, in, bsize, 0); - desc->prfn(desc, dst, src, bsize); - scatterwalk_copychunks(dst, out, bsize, 1); - - return bsize; -} - -static inline unsigned int crypt_fast(const struct cipher_desc *desc, - struct scatter_walk *in, - struct scatter_walk *out, - unsigned int nbytes, u8 *tmp) -{ - u8 *src, *dst; - u8 *real_src, *real_dst; - - real_src = scatterwalk_map(in, 0); - real_dst = scatterwalk_map(out, 1); - - src = real_src; - dst = scatterwalk_samebuf(in, out) ? src : real_dst; - - if (tmp) { - memcpy(tmp, src, nbytes); - src = tmp; - dst = tmp; - } - - nbytes = desc->prfn(desc, dst, src, nbytes); - - if (tmp) - memcpy(real_dst, tmp, nbytes); - - scatterwalk_unmap(real_src, 0); - scatterwalk_unmap(real_dst, 1); - - scatterwalk_advance(in, nbytes); - scatterwalk_advance(out, nbytes); - - return nbytes; -} - -/* - * Generic encrypt/decrypt wrapper for ciphers, handles operations across - * multiple page boundaries by using temporary blocks. In user context, - * the kernel is given a chance to schedule us once per page. - */ -static int crypt(const struct cipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct scatter_walk walk_in, walk_out; - struct crypto_tfm *tfm = desc->tfm; - const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); - unsigned int alignmask = crypto_tfm_alg_alignmask(tfm); - unsigned long buffer = 0; - - if (!nbytes) - return 0; - - if (nbytes % bsize) { - tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; - return -EINVAL; - } - - scatterwalk_start(&walk_in, src); - scatterwalk_start(&walk_out, dst); - - for(;;) { - unsigned int n = nbytes; - u8 *tmp = NULL; - - if (!scatterwalk_aligned(&walk_in, alignmask) || - !scatterwalk_aligned(&walk_out, alignmask)) { - if (!buffer) { - buffer = __get_free_page(GFP_ATOMIC); - if (!buffer) - n = 0; - } - tmp = (u8 *)buffer; - } - - n = scatterwalk_clamp(&walk_in, n); - n = scatterwalk_clamp(&walk_out, n); - - if (likely(n >= bsize)) - n = crypt_fast(desc, &walk_in, &walk_out, n, tmp); - else - n = crypt_slow(desc, &walk_in, &walk_out, bsize); - - nbytes -= n; - - scatterwalk_done(&walk_in, 0, nbytes); - scatterwalk_done(&walk_out, 1, nbytes); - - if (!nbytes) - break; - - crypto_yield(tfm->crt_flags); - } - - if (buffer) - free_page(buffer); - - return 0; -} - -static int crypt_iv_unaligned(struct cipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - u8 *iv = desc->info; - - if (unlikely(((unsigned long)iv & alignmask))) { - unsigned int ivsize = tfm->crt_cipher.cit_ivsize; - u8 buffer[ivsize + alignmask]; - u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - int err; - - desc->info = memcpy(tmp, iv, ivsize); - err = crypt(desc, dst, src, nbytes); - memcpy(iv, tmp, ivsize); - - return err; - } - - return crypt(desc, dst, src, nbytes); -} - -static unsigned int cbc_process_encrypt(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block; - int bsize = crypto_tfm_alg_blocksize(tfm); - - void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn; - u8 *iv = desc->info; - unsigned int done = 0; - - nbytes -= bsize; - - do { - xor(iv, src); - fn(tfm, dst, iv); - memcpy(iv, dst, bsize); - - src += bsize; - dst += bsize; - } while ((done += bsize) <= nbytes); - - return done; -} - -static unsigned int cbc_process_decrypt(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block; - int bsize = crypto_tfm_alg_blocksize(tfm); - unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm); - - u8 stack[src == dst ? bsize + alignmask : 0]; - u8 *buf = (u8 *)ALIGN((unsigned long)stack, alignmask + 1); - u8 **dst_p = src == dst ? &buf : &dst; - - void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn; - u8 *iv = desc->info; - unsigned int done = 0; - - nbytes -= bsize; - - do { - u8 *tmp_dst = *dst_p; - - fn(tfm, tmp_dst, src); - xor(tmp_dst, iv); - memcpy(iv, src, bsize); - if (tmp_dst != dst) - memcpy(dst, tmp_dst, bsize); - - src += bsize; - dst += bsize; - } while ((done += bsize) <= nbytes); - - return done; -} - -static unsigned int ecb_process(const struct cipher_desc *desc, u8 *dst, - const u8 *src, unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - int bsize = crypto_tfm_alg_blocksize(tfm); - void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn; - unsigned int done = 0; - - nbytes -= bsize; - - do { - fn(tfm, dst, src); - - src += bsize; - dst += bsize; - } while ((done += bsize) <= nbytes); - - return done; -} static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { @@ -293,122 +32,6 @@ static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) return cia->cia_setkey(tfm, key, keylen); } -static int ecb_encrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_encrypt; - desc.prfn = cipher->cia_encrypt_ecb ?: ecb_process; - - return crypt(&desc, dst, src, nbytes); -} - -static int ecb_decrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_decrypt; - desc.prfn = cipher->cia_decrypt_ecb ?: ecb_process; - - return crypt(&desc, dst, src, nbytes); -} - -static int cbc_encrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_encrypt; - desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt; - desc.info = tfm->crt_cipher.cit_iv; - - return crypt(&desc, dst, src, nbytes); -} - -static int cbc_encrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_encrypt; - desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt; - desc.info = iv; - - return crypt_iv_unaligned(&desc, dst, src, nbytes); -} - -static int cbc_decrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_decrypt; - desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt; - desc.info = tfm->crt_cipher.cit_iv; - - return crypt(&desc, dst, src, nbytes); -} - -static int cbc_decrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_decrypt; - desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt; - desc.info = iv; - - return crypt_iv_unaligned(&desc, dst, src, nbytes); -} - -static int nocrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - return -ENOSYS; -} - -static int nocrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - return -ENOSYS; -} - -int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) -{ - u32 mode = flags & CRYPTO_TFM_MODE_MASK; - tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB; - return 0; -} - static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *, const u8 *), struct crypto_tfm *tfm, @@ -454,7 +77,6 @@ static void cipher_decrypt_unaligned(struct crypto_tfm *tfm, int crypto_init_cipher_ops(struct crypto_tfm *tfm) { - int ret = 0; struct cipher_tfm *ops = &tfm->crt_cipher; struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; @@ -464,70 +86,7 @@ int crypto_init_cipher_ops(struct crypto_tfm *tfm) ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ? cipher_decrypt_unaligned : cipher->cia_decrypt; - switch (tfm->crt_cipher.cit_mode) { - case CRYPTO_TFM_MODE_ECB: - ops->cit_encrypt = ecb_encrypt; - ops->cit_decrypt = ecb_decrypt; - ops->cit_encrypt_iv = nocrypt_iv; - ops->cit_decrypt_iv = nocrypt_iv; - break; - - case CRYPTO_TFM_MODE_CBC: - ops->cit_encrypt = cbc_encrypt; - ops->cit_decrypt = cbc_decrypt; - ops->cit_encrypt_iv = cbc_encrypt_iv; - ops->cit_decrypt_iv = cbc_decrypt_iv; - break; - - case CRYPTO_TFM_MODE_CFB: - ops->cit_encrypt = nocrypt; - ops->cit_decrypt = nocrypt; - ops->cit_encrypt_iv = nocrypt_iv; - ops->cit_decrypt_iv = nocrypt_iv; - break; - - case CRYPTO_TFM_MODE_CTR: - ops->cit_encrypt = nocrypt; - ops->cit_decrypt = nocrypt; - ops->cit_encrypt_iv = nocrypt_iv; - ops->cit_decrypt_iv = nocrypt_iv; - break; - - default: - BUG(); - } - - if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) { - unsigned long align; - unsigned long addr; - - switch (crypto_tfm_alg_blocksize(tfm)) { - case 8: - ops->cit_xor_block = xor_64; - break; - - case 16: - ops->cit_xor_block = xor_128; - break; - - default: - printk(KERN_WARNING "%s: block size %u not supported\n", - crypto_tfm_alg_name(tfm), - crypto_tfm_alg_blocksize(tfm)); - ret = -EINVAL; - goto out; - } - - ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm); - align = crypto_tfm_alg_alignmask(tfm) + 1; - addr = (unsigned long)crypto_tfm_ctx(tfm); - addr = ALIGN(addr, align); - addr += ALIGN(tfm->__crt_alg->cra_ctxsize, align); - ops->cit_iv = (void *)addr; - } - -out: - return ret; + return 0; } void crypto_exit_cipher_ops(struct crypto_tfm *tfm) diff --git a/trunk/crypto/compress.c b/trunk/crypto/compress.c index eca182aa3380..0a6570048c1e 100644 --- a/trunk/crypto/compress.c +++ b/trunk/crypto/compress.c @@ -34,11 +34,6 @@ static int crypto_decompress(struct crypto_tfm *tfm, dlen); } -int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) -{ - return flags ? -EINVAL : 0; -} - int crypto_init_compress_ops(struct crypto_tfm *tfm) { struct compress_tfm *ops = &tfm->crt_compress; diff --git a/trunk/crypto/digest.c b/trunk/crypto/digest.c index 8f4593268ce0..1bf7414aeb9e 100644 --- a/trunk/crypto/digest.c +++ b/trunk/crypto/digest.c @@ -14,7 +14,9 @@ #include #include +#include #include +#include #include #include @@ -29,8 +31,8 @@ static int init(struct hash_desc *desc) return 0; } -static int update(struct hash_desc *desc, - struct scatterlist *sg, unsigned int nbytes) +static int update2(struct hash_desc *desc, + struct scatterlist *sg, unsigned int nbytes) { struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); unsigned int alignmask = crypto_tfm_alg_alignmask(tfm); @@ -81,6 +83,14 @@ static int update(struct hash_desc *desc, return 0; } +static int update(struct hash_desc *desc, + struct scatterlist *sg, unsigned int nbytes) +{ + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + return update2(desc, sg, nbytes); +} + static int final(struct hash_desc *desc, u8 *out) { struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); @@ -118,16 +128,14 @@ static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen) static int digest(struct hash_desc *desc, struct scatterlist *sg, unsigned int nbytes, u8 *out) { + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + init(desc); - update(desc, sg, nbytes); + update2(desc, sg, nbytes); return final(desc, out); } -int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) -{ - return flags ? -EINVAL : 0; -} - int crypto_init_digest_ops(struct crypto_tfm *tfm) { struct hash_tfm *ops = &tfm->crt_hash; diff --git a/trunk/crypto/ecb.c b/trunk/crypto/ecb.c index f239aa9c4017..839a0aed8c22 100644 --- a/trunk/crypto/ecb.c +++ b/trunk/crypto/ecb.c @@ -99,12 +99,13 @@ static int crypto_ecb_init_tfm(struct crypto_tfm *tfm) struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct crypto_ecb_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); - ctx->child = crypto_cipher_cast(tfm); + ctx->child = cipher; return 0; } diff --git a/trunk/crypto/fcrypt.c b/trunk/crypto/fcrypt.c new file mode 100644 index 000000000000..9c2bb535b09a --- /dev/null +++ b/trunk/crypto/fcrypt.c @@ -0,0 +1,423 @@ +/* FCrypt encryption algorithm + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Based on code: + * + * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#define ROUNDS 16 + +struct fcrypt_ctx { + u32 sched[ROUNDS]; +}; + +/* Rotate right two 32 bit numbers as a 56 bit number */ +#define ror56(hi, lo, n) \ +do { \ + u32 t = lo & ((1 << n) - 1); \ + lo = (lo >> n) | ((hi & ((1 << n) - 1)) << (32 - n)); \ + hi = (hi >> n) | (t << (24-n)); \ +} while(0) + +/* Rotate right one 64 bit number as a 56 bit number */ +#define ror56_64(k, n) \ +do { \ + k = (k >> n) | ((k & ((1 << n) - 1)) << (56 - n)); \ +} while(0) + +/* + * Sboxes for Feistel network derived from + * /afs/transarc.com/public/afsps/afs.rel31b.export-src/rxkad/sboxes.h + */ +#undef Z +#define Z(x) __constant_be32_to_cpu(x << 3) +static const u32 sbox0[256] = { + Z(0xea), Z(0x7f), Z(0xb2), Z(0x64), Z(0x9d), Z(0xb0), Z(0xd9), Z(0x11), + Z(0xcd), Z(0x86), Z(0x86), Z(0x91), Z(0x0a), Z(0xb2), Z(0x93), Z(0x06), + Z(0x0e), Z(0x06), Z(0xd2), Z(0x65), Z(0x73), Z(0xc5), Z(0x28), Z(0x60), + Z(0xf2), Z(0x20), Z(0xb5), Z(0x38), Z(0x7e), Z(0xda), Z(0x9f), Z(0xe3), + Z(0xd2), Z(0xcf), Z(0xc4), Z(0x3c), Z(0x61), Z(0xff), Z(0x4a), Z(0x4a), + Z(0x35), Z(0xac), Z(0xaa), Z(0x5f), Z(0x2b), Z(0xbb), Z(0xbc), Z(0x53), + Z(0x4e), Z(0x9d), Z(0x78), Z(0xa3), Z(0xdc), Z(0x09), Z(0x32), Z(0x10), + Z(0xc6), Z(0x6f), Z(0x66), Z(0xd6), Z(0xab), Z(0xa9), Z(0xaf), Z(0xfd), + Z(0x3b), Z(0x95), Z(0xe8), Z(0x34), Z(0x9a), Z(0x81), Z(0x72), Z(0x80), + Z(0x9c), Z(0xf3), Z(0xec), Z(0xda), Z(0x9f), Z(0x26), Z(0x76), Z(0x15), + Z(0x3e), Z(0x55), Z(0x4d), Z(0xde), Z(0x84), Z(0xee), Z(0xad), Z(0xc7), + Z(0xf1), Z(0x6b), Z(0x3d), Z(0xd3), Z(0x04), Z(0x49), Z(0xaa), Z(0x24), + Z(0x0b), Z(0x8a), Z(0x83), Z(0xba), Z(0xfa), Z(0x85), Z(0xa0), Z(0xa8), + Z(0xb1), Z(0xd4), Z(0x01), Z(0xd8), Z(0x70), Z(0x64), Z(0xf0), Z(0x51), + Z(0xd2), Z(0xc3), Z(0xa7), Z(0x75), Z(0x8c), Z(0xa5), Z(0x64), Z(0xef), + Z(0x10), Z(0x4e), Z(0xb7), Z(0xc6), Z(0x61), Z(0x03), Z(0xeb), Z(0x44), + Z(0x3d), Z(0xe5), Z(0xb3), Z(0x5b), Z(0xae), Z(0xd5), Z(0xad), Z(0x1d), + Z(0xfa), Z(0x5a), Z(0x1e), Z(0x33), Z(0xab), Z(0x93), Z(0xa2), Z(0xb7), + Z(0xe7), Z(0xa8), Z(0x45), Z(0xa4), Z(0xcd), Z(0x29), Z(0x63), Z(0x44), + Z(0xb6), Z(0x69), Z(0x7e), Z(0x2e), Z(0x62), Z(0x03), Z(0xc8), Z(0xe0), + Z(0x17), Z(0xbb), Z(0xc7), Z(0xf3), Z(0x3f), Z(0x36), Z(0xba), Z(0x71), + Z(0x8e), Z(0x97), Z(0x65), Z(0x60), Z(0x69), Z(0xb6), Z(0xf6), Z(0xe6), + Z(0x6e), Z(0xe0), Z(0x81), Z(0x59), Z(0xe8), Z(0xaf), Z(0xdd), Z(0x95), + Z(0x22), Z(0x99), Z(0xfd), Z(0x63), Z(0x19), Z(0x74), Z(0x61), Z(0xb1), + Z(0xb6), Z(0x5b), Z(0xae), Z(0x54), Z(0xb3), Z(0x70), Z(0xff), Z(0xc6), + Z(0x3b), Z(0x3e), Z(0xc1), Z(0xd7), Z(0xe1), Z(0x0e), Z(0x76), Z(0xe5), + Z(0x36), Z(0x4f), Z(0x59), Z(0xc7), Z(0x08), Z(0x6e), Z(0x82), Z(0xa6), + Z(0x93), Z(0xc4), Z(0xaa), Z(0x26), Z(0x49), Z(0xe0), Z(0x21), Z(0x64), + Z(0x07), Z(0x9f), Z(0x64), Z(0x81), Z(0x9c), Z(0xbf), Z(0xf9), Z(0xd1), + Z(0x43), Z(0xf8), Z(0xb6), Z(0xb9), Z(0xf1), Z(0x24), Z(0x75), Z(0x03), + Z(0xe4), Z(0xb0), Z(0x99), Z(0x46), Z(0x3d), Z(0xf5), Z(0xd1), Z(0x39), + Z(0x72), Z(0x12), Z(0xf6), Z(0xba), Z(0x0c), Z(0x0d), Z(0x42), Z(0x2e) +}; + +#undef Z +#define Z(x) __constant_be32_to_cpu((x << 27) | (x >> 5)) +static const u32 sbox1[256] = { + Z(0x77), Z(0x14), Z(0xa6), Z(0xfe), Z(0xb2), Z(0x5e), Z(0x8c), Z(0x3e), + Z(0x67), Z(0x6c), Z(0xa1), Z(0x0d), Z(0xc2), Z(0xa2), Z(0xc1), Z(0x85), + Z(0x6c), Z(0x7b), Z(0x67), Z(0xc6), Z(0x23), Z(0xe3), Z(0xf2), Z(0x89), + Z(0x50), Z(0x9c), Z(0x03), Z(0xb7), Z(0x73), Z(0xe6), Z(0xe1), Z(0x39), + Z(0x31), Z(0x2c), Z(0x27), Z(0x9f), Z(0xa5), Z(0x69), Z(0x44), Z(0xd6), + Z(0x23), Z(0x83), Z(0x98), Z(0x7d), Z(0x3c), Z(0xb4), Z(0x2d), Z(0x99), + Z(0x1c), Z(0x1f), Z(0x8c), Z(0x20), Z(0x03), Z(0x7c), Z(0x5f), Z(0xad), + Z(0xf4), Z(0xfa), Z(0x95), Z(0xca), Z(0x76), Z(0x44), Z(0xcd), Z(0xb6), + Z(0xb8), Z(0xa1), Z(0xa1), Z(0xbe), Z(0x9e), Z(0x54), Z(0x8f), Z(0x0b), + Z(0x16), Z(0x74), Z(0x31), Z(0x8a), Z(0x23), Z(0x17), Z(0x04), Z(0xfa), + Z(0x79), Z(0x84), Z(0xb1), Z(0xf5), Z(0x13), Z(0xab), Z(0xb5), Z(0x2e), + Z(0xaa), Z(0x0c), Z(0x60), Z(0x6b), Z(0x5b), Z(0xc4), Z(0x4b), Z(0xbc), + Z(0xe2), Z(0xaf), Z(0x45), Z(0x73), Z(0xfa), Z(0xc9), Z(0x49), Z(0xcd), + Z(0x00), Z(0x92), Z(0x7d), Z(0x97), Z(0x7a), Z(0x18), Z(0x60), Z(0x3d), + Z(0xcf), Z(0x5b), Z(0xde), Z(0xc6), Z(0xe2), Z(0xe6), Z(0xbb), Z(0x8b), + Z(0x06), Z(0xda), Z(0x08), Z(0x15), Z(0x1b), Z(0x88), Z(0x6a), Z(0x17), + Z(0x89), Z(0xd0), Z(0xa9), Z(0xc1), Z(0xc9), Z(0x70), Z(0x6b), Z(0xe5), + Z(0x43), Z(0xf4), Z(0x68), Z(0xc8), Z(0xd3), Z(0x84), Z(0x28), Z(0x0a), + Z(0x52), Z(0x66), Z(0xa3), Z(0xca), Z(0xf2), Z(0xe3), Z(0x7f), Z(0x7a), + Z(0x31), Z(0xf7), Z(0x88), Z(0x94), Z(0x5e), Z(0x9c), Z(0x63), Z(0xd5), + Z(0x24), Z(0x66), Z(0xfc), Z(0xb3), Z(0x57), Z(0x25), Z(0xbe), Z(0x89), + Z(0x44), Z(0xc4), Z(0xe0), Z(0x8f), Z(0x23), Z(0x3c), Z(0x12), Z(0x52), + Z(0xf5), Z(0x1e), Z(0xf4), Z(0xcb), Z(0x18), Z(0x33), Z(0x1f), Z(0xf8), + Z(0x69), Z(0x10), Z(0x9d), Z(0xd3), Z(0xf7), Z(0x28), Z(0xf8), Z(0x30), + Z(0x05), Z(0x5e), Z(0x32), Z(0xc0), Z(0xd5), Z(0x19), Z(0xbd), Z(0x45), + Z(0x8b), Z(0x5b), Z(0xfd), Z(0xbc), Z(0xe2), Z(0x5c), Z(0xa9), Z(0x96), + Z(0xef), Z(0x70), Z(0xcf), Z(0xc2), Z(0x2a), Z(0xb3), Z(0x61), Z(0xad), + Z(0x80), Z(0x48), Z(0x81), Z(0xb7), Z(0x1d), Z(0x43), Z(0xd9), Z(0xd7), + Z(0x45), Z(0xf0), Z(0xd8), Z(0x8a), Z(0x59), Z(0x7c), Z(0x57), Z(0xc1), + Z(0x79), Z(0xc7), Z(0x34), Z(0xd6), Z(0x43), Z(0xdf), Z(0xe4), Z(0x78), + Z(0x16), Z(0x06), Z(0xda), Z(0x92), Z(0x76), Z(0x51), Z(0xe1), Z(0xd4), + Z(0x70), Z(0x03), Z(0xe0), Z(0x2f), Z(0x96), Z(0x91), Z(0x82), Z(0x80) +}; + +#undef Z +#define Z(x) __constant_be32_to_cpu(x << 11) +static const u32 sbox2[256] = { + Z(0xf0), Z(0x37), Z(0x24), Z(0x53), Z(0x2a), Z(0x03), Z(0x83), Z(0x86), + Z(0xd1), Z(0xec), Z(0x50), Z(0xf0), Z(0x42), Z(0x78), Z(0x2f), Z(0x6d), + Z(0xbf), Z(0x80), Z(0x87), Z(0x27), Z(0x95), Z(0xe2), Z(0xc5), Z(0x5d), + Z(0xf9), Z(0x6f), Z(0xdb), Z(0xb4), Z(0x65), Z(0x6e), Z(0xe7), Z(0x24), + Z(0xc8), Z(0x1a), Z(0xbb), Z(0x49), Z(0xb5), Z(0x0a), Z(0x7d), Z(0xb9), + Z(0xe8), Z(0xdc), Z(0xb7), Z(0xd9), Z(0x45), Z(0x20), Z(0x1b), Z(0xce), + Z(0x59), Z(0x9d), Z(0x6b), Z(0xbd), Z(0x0e), Z(0x8f), Z(0xa3), Z(0xa9), + Z(0xbc), Z(0x74), Z(0xa6), Z(0xf6), Z(0x7f), Z(0x5f), Z(0xb1), Z(0x68), + Z(0x84), Z(0xbc), Z(0xa9), Z(0xfd), Z(0x55), Z(0x50), Z(0xe9), Z(0xb6), + Z(0x13), Z(0x5e), Z(0x07), Z(0xb8), Z(0x95), Z(0x02), Z(0xc0), Z(0xd0), + Z(0x6a), Z(0x1a), Z(0x85), Z(0xbd), Z(0xb6), Z(0xfd), Z(0xfe), Z(0x17), + Z(0x3f), Z(0x09), Z(0xa3), Z(0x8d), Z(0xfb), Z(0xed), Z(0xda), Z(0x1d), + Z(0x6d), Z(0x1c), Z(0x6c), Z(0x01), Z(0x5a), Z(0xe5), Z(0x71), Z(0x3e), + Z(0x8b), Z(0x6b), Z(0xbe), Z(0x29), Z(0xeb), Z(0x12), Z(0x19), Z(0x34), + Z(0xcd), Z(0xb3), Z(0xbd), Z(0x35), Z(0xea), Z(0x4b), Z(0xd5), Z(0xae), + Z(0x2a), Z(0x79), Z(0x5a), Z(0xa5), Z(0x32), Z(0x12), Z(0x7b), Z(0xdc), + Z(0x2c), Z(0xd0), Z(0x22), Z(0x4b), Z(0xb1), Z(0x85), Z(0x59), Z(0x80), + Z(0xc0), Z(0x30), Z(0x9f), Z(0x73), Z(0xd3), Z(0x14), Z(0x48), Z(0x40), + Z(0x07), Z(0x2d), Z(0x8f), Z(0x80), Z(0x0f), Z(0xce), Z(0x0b), Z(0x5e), + Z(0xb7), Z(0x5e), Z(0xac), Z(0x24), Z(0x94), Z(0x4a), Z(0x18), Z(0x15), + Z(0x05), Z(0xe8), Z(0x02), Z(0x77), Z(0xa9), Z(0xc7), Z(0x40), Z(0x45), + Z(0x89), Z(0xd1), Z(0xea), Z(0xde), Z(0x0c), Z(0x79), Z(0x2a), Z(0x99), + Z(0x6c), Z(0x3e), Z(0x95), Z(0xdd), Z(0x8c), Z(0x7d), Z(0xad), Z(0x6f), + Z(0xdc), Z(0xff), Z(0xfd), Z(0x62), Z(0x47), Z(0xb3), Z(0x21), Z(0x8a), + Z(0xec), Z(0x8e), Z(0x19), Z(0x18), Z(0xb4), Z(0x6e), Z(0x3d), Z(0xfd), + Z(0x74), Z(0x54), Z(0x1e), Z(0x04), Z(0x85), Z(0xd8), Z(0xbc), Z(0x1f), + Z(0x56), Z(0xe7), Z(0x3a), Z(0x56), Z(0x67), Z(0xd6), Z(0xc8), Z(0xa5), + Z(0xf3), Z(0x8e), Z(0xde), Z(0xae), Z(0x37), Z(0x49), Z(0xb7), Z(0xfa), + Z(0xc8), Z(0xf4), Z(0x1f), Z(0xe0), Z(0x2a), Z(0x9b), Z(0x15), Z(0xd1), + Z(0x34), Z(0x0e), Z(0xb5), Z(0xe0), Z(0x44), Z(0x78), Z(0x84), Z(0x59), + Z(0x56), Z(0x68), Z(0x77), Z(0xa5), Z(0x14), Z(0x06), Z(0xf5), Z(0x2f), + Z(0x8c), Z(0x8a), Z(0x73), Z(0x80), Z(0x76), Z(0xb4), Z(0x10), Z(0x86) +}; + +#undef Z +#define Z(x) __constant_be32_to_cpu(x << 19) +static const u32 sbox3[256] = { + Z(0xa9), Z(0x2a), Z(0x48), Z(0x51), Z(0x84), Z(0x7e), Z(0x49), Z(0xe2), + Z(0xb5), Z(0xb7), Z(0x42), Z(0x33), Z(0x7d), Z(0x5d), Z(0xa6), Z(0x12), + Z(0x44), Z(0x48), Z(0x6d), Z(0x28), Z(0xaa), Z(0x20), Z(0x6d), Z(0x57), + Z(0xd6), Z(0x6b), Z(0x5d), Z(0x72), Z(0xf0), Z(0x92), Z(0x5a), Z(0x1b), + Z(0x53), Z(0x80), Z(0x24), Z(0x70), Z(0x9a), Z(0xcc), Z(0xa7), Z(0x66), + Z(0xa1), Z(0x01), Z(0xa5), Z(0x41), Z(0x97), Z(0x41), Z(0x31), Z(0x82), + Z(0xf1), Z(0x14), Z(0xcf), Z(0x53), Z(0x0d), Z(0xa0), Z(0x10), Z(0xcc), + Z(0x2a), Z(0x7d), Z(0xd2), Z(0xbf), Z(0x4b), Z(0x1a), Z(0xdb), Z(0x16), + Z(0x47), Z(0xf6), Z(0x51), Z(0x36), Z(0xed), Z(0xf3), Z(0xb9), Z(0x1a), + Z(0xa7), Z(0xdf), Z(0x29), Z(0x43), Z(0x01), Z(0x54), Z(0x70), Z(0xa4), + Z(0xbf), Z(0xd4), Z(0x0b), Z(0x53), Z(0x44), Z(0x60), Z(0x9e), Z(0x23), + Z(0xa1), Z(0x18), Z(0x68), Z(0x4f), Z(0xf0), Z(0x2f), Z(0x82), Z(0xc2), + Z(0x2a), Z(0x41), Z(0xb2), Z(0x42), Z(0x0c), Z(0xed), Z(0x0c), Z(0x1d), + Z(0x13), Z(0x3a), Z(0x3c), Z(0x6e), Z(0x35), Z(0xdc), Z(0x60), Z(0x65), + Z(0x85), Z(0xe9), Z(0x64), Z(0x02), Z(0x9a), Z(0x3f), Z(0x9f), Z(0x87), + Z(0x96), Z(0xdf), Z(0xbe), Z(0xf2), Z(0xcb), Z(0xe5), Z(0x6c), Z(0xd4), + Z(0x5a), Z(0x83), Z(0xbf), Z(0x92), Z(0x1b), Z(0x94), Z(0x00), Z(0x42), + Z(0xcf), Z(0x4b), Z(0x00), Z(0x75), Z(0xba), Z(0x8f), Z(0x76), Z(0x5f), + Z(0x5d), Z(0x3a), Z(0x4d), Z(0x09), Z(0x12), Z(0x08), Z(0x38), Z(0x95), + Z(0x17), Z(0xe4), Z(0x01), Z(0x1d), Z(0x4c), Z(0xa9), Z(0xcc), Z(0x85), + Z(0x82), Z(0x4c), Z(0x9d), Z(0x2f), Z(0x3b), Z(0x66), Z(0xa1), Z(0x34), + Z(0x10), Z(0xcd), Z(0x59), Z(0x89), Z(0xa5), Z(0x31), Z(0xcf), Z(0x05), + Z(0xc8), Z(0x84), Z(0xfa), Z(0xc7), Z(0xba), Z(0x4e), Z(0x8b), Z(0x1a), + Z(0x19), Z(0xf1), Z(0xa1), Z(0x3b), Z(0x18), Z(0x12), Z(0x17), Z(0xb0), + Z(0x98), Z(0x8d), Z(0x0b), Z(0x23), Z(0xc3), Z(0x3a), Z(0x2d), Z(0x20), + Z(0xdf), Z(0x13), Z(0xa0), Z(0xa8), Z(0x4c), Z(0x0d), Z(0x6c), Z(0x2f), + Z(0x47), Z(0x13), Z(0x13), Z(0x52), Z(0x1f), Z(0x2d), Z(0xf5), Z(0x79), + Z(0x3d), Z(0xa2), Z(0x54), Z(0xbd), Z(0x69), Z(0xc8), Z(0x6b), Z(0xf3), + Z(0x05), Z(0x28), Z(0xf1), Z(0x16), Z(0x46), Z(0x40), Z(0xb0), Z(0x11), + Z(0xd3), Z(0xb7), Z(0x95), Z(0x49), Z(0xcf), Z(0xc3), Z(0x1d), Z(0x8f), + Z(0xd8), Z(0xe1), Z(0x73), Z(0xdb), Z(0xad), Z(0xc8), Z(0xc9), Z(0xa9), + Z(0xa1), Z(0xc2), Z(0xc5), Z(0xe3), Z(0xba), Z(0xfc), Z(0x0e), Z(0x25) +}; + +/* + * This is a 16 round Feistel network with permutation F_ENCRYPT + */ +#define F_ENCRYPT(R, L, sched) \ +do { \ + union lc4 { u32 l; u8 c[4]; } u; \ + u.l = sched ^ R; \ + L ^= sbox0[u.c[0]] ^ sbox1[u.c[1]] ^ sbox2[u.c[2]] ^ sbox3[u.c[3]]; \ +} while(0) + +/* + * encryptor + */ +static void fcrypt_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + const struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm); + struct { + u32 l, r; + } X; + + memcpy(&X, src, sizeof(X)); + + F_ENCRYPT(X.r, X.l, ctx->sched[0x0]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x1]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x2]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x3]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x4]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x5]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x6]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x7]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x8]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x9]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xa]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xb]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xc]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xd]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xe]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xf]); + + memcpy(dst, &X, sizeof(X)); +} + +/* + * decryptor + */ +static void fcrypt_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + const struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm); + struct { + u32 l, r; + } X; + + memcpy(&X, src, sizeof(X)); + + F_ENCRYPT(X.l, X.r, ctx->sched[0xf]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xe]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xd]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xc]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xb]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xa]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x9]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x8]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x7]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x6]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x5]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x4]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x3]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x2]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x1]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x0]); + + memcpy(dst, &X, sizeof(X)); +} + +/* + * Generate a key schedule from key, the least significant bit in each key byte + * is parity and shall be ignored. This leaves 56 significant bits in the key + * to scatter over the 16 key schedules. For each schedule extract the low + * order 32 bits and use as schedule, then rotate right by 11 bits. + */ +static int fcrypt_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +{ + struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm); + +#if BITS_PER_LONG == 64 /* the 64-bit version can also be used for 32-bit + * kernels - it seems to be faster but the code is + * larger */ + + u64 k; /* k holds all 56 non-parity bits */ + + /* discard the parity bits */ + k = (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key) >> 1; + + /* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */ + ctx->sched[0x0] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x1] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x2] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x3] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x4] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x5] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x6] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x7] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x8] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x9] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xa] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xb] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xc] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xd] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xe] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xf] = be32_to_cpu(k); + + return 0; +#else + u32 hi, lo; /* hi is upper 24 bits and lo lower 32, total 56 */ + + /* discard the parity bits */ + lo = (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + hi = lo >> 4; + lo &= 0xf; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key) >> 1; + + /* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */ + ctx->sched[0x0] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x1] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x2] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x3] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x4] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x5] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x6] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x7] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x8] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x9] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xa] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xb] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xc] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xd] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xe] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xf] = be32_to_cpu(lo); + return 0; +#endif +} + +static struct crypto_alg fcrypt_alg = { + .cra_name = "fcrypt", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = 8, + .cra_ctxsize = sizeof(struct fcrypt_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(fcrypt_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = 8, + .cia_max_keysize = 8, + .cia_setkey = fcrypt_setkey, + .cia_encrypt = fcrypt_encrypt, + .cia_decrypt = fcrypt_decrypt } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&fcrypt_alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&fcrypt_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FCrypt Cipher Algorithm"); +MODULE_AUTHOR("David Howells "); diff --git a/trunk/crypto/hash.c b/trunk/crypto/hash.c index cdec23d885fe..12c4514f3478 100644 --- a/trunk/crypto/hash.c +++ b/trunk/crypto/hash.c @@ -16,12 +16,13 @@ #include "internal.h" -static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg) +static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg, u32 type, + u32 mask) { return alg->cra_ctxsize; } -static int crypto_init_hash_ops(struct crypto_tfm *tfm) +static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { struct hash_tfm *crt = &tfm->crt_hash; struct hash_alg *alg = &tfm->__crt_alg->cra_hash; diff --git a/trunk/crypto/hmac.c b/trunk/crypto/hmac.c index b521bcd2b2c6..44187c5ee593 100644 --- a/trunk/crypto/hmac.c +++ b/trunk/crypto/hmac.c @@ -172,15 +172,16 @@ static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg, static int hmac_init_tfm(struct crypto_tfm *tfm) { + struct crypto_hash *hash; struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm)); - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + hash = crypto_spawn_hash(spawn); + if (IS_ERR(hash)) + return PTR_ERR(hash); - ctx->child = crypto_hash_cast(tfm); + ctx->child = hash; return 0; } diff --git a/trunk/crypto/internal.h b/trunk/crypto/internal.h index 2da6ad4f3593..60acad9788c5 100644 --- a/trunk/crypto/internal.h +++ b/trunk/crypto/internal.h @@ -83,8 +83,7 @@ static inline void crypto_exit_proc(void) { } #endif -static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg, - int flags) +static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg) { unsigned int len = alg->cra_ctxsize; @@ -96,23 +95,12 @@ static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg, return len; } -static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg, - int flags) +static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg) { - unsigned int len = alg->cra_ctxsize; - - switch (flags & CRYPTO_TFM_MODE_MASK) { - case CRYPTO_TFM_MODE_CBC: - len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1); - len += alg->cra_blocksize; - break; - } - - return len; + return alg->cra_ctxsize; } -static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg, - int flags) +static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg) { return alg->cra_ctxsize; } @@ -121,10 +109,6 @@ struct crypto_alg *crypto_mod_get(struct crypto_alg *alg); struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask); struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask); -int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); -int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); -int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); - int crypto_init_digest_ops(struct crypto_tfm *tfm); int crypto_init_cipher_ops(struct crypto_tfm *tfm); int crypto_init_compress_ops(struct crypto_tfm *tfm); @@ -136,7 +120,8 @@ void crypto_exit_compress_ops(struct crypto_tfm *tfm); void crypto_larval_error(const char *name, u32 type, u32 mask); void crypto_shoot_alg(struct crypto_alg *alg); -struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags); +struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, + u32 mask); int crypto_register_instance(struct crypto_template *tmpl, struct crypto_instance *inst); diff --git a/trunk/crypto/lrw.c b/trunk/crypto/lrw.c index 56642586d84f..b4105080ac7a 100644 --- a/trunk/crypto/lrw.c +++ b/trunk/crypto/lrw.c @@ -201,21 +201,22 @@ static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, static int init_tfm(struct crypto_tfm *tfm) { + struct crypto_cipher *cipher; struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct priv *ctx = crypto_tfm_ctx(tfm); u32 *flags = &tfm->crt_flags; - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); - if (crypto_tfm_alg_blocksize(tfm) != 16) { + if (crypto_cipher_blocksize(cipher) != 16) { *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; return -EINVAL; } - ctx->child = crypto_cipher_cast(tfm); + ctx->child = cipher; return 0; } diff --git a/trunk/crypto/pcbc.c b/trunk/crypto/pcbc.c new file mode 100644 index 000000000000..5174d7fdad6e --- /dev/null +++ b/trunk/crypto/pcbc.c @@ -0,0 +1,349 @@ +/* + * PCBC: Propagating Cipher Block Chaining mode + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * Derived from cbc.c + * - Copyright (c) 2006 Herbert Xu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +struct crypto_pcbc_ctx { + struct crypto_cipher *child; + void (*xor)(u8 *dst, const u8 *src, unsigned int bs); +}; + +static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(parent); + struct crypto_cipher *child = ctx->child; + int err; + + crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(child, key, keylen); + crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + return err; +} + +static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_cipher *tfm, + void (*xor)(u8 *, const u8 *, + unsigned int)) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_encrypt; + int bsize = crypto_cipher_blocksize(tfm); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + u8 *iv = walk->iv; + + do { + xor(iv, src, bsize); + fn(crypto_cipher_tfm(tfm), dst, iv); + memcpy(iv, dst, bsize); + xor(iv, src, bsize); + + src += bsize; + dst += bsize; + } while ((nbytes -= bsize) >= bsize); + + return nbytes; +} + +static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_cipher *tfm, + void (*xor)(u8 *, const u8 *, + unsigned int)) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_encrypt; + int bsize = crypto_cipher_blocksize(tfm); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *iv = walk->iv; + u8 tmpbuf[bsize]; + + do { + memcpy(tmpbuf, src, bsize); + xor(iv, tmpbuf, bsize); + fn(crypto_cipher_tfm(tfm), src, iv); + memcpy(iv, src, bsize); + xor(iv, tmpbuf, bsize); + + src += bsize; + } while ((nbytes -= bsize) >= bsize); + + memcpy(walk->iv, iv, bsize); + + return nbytes; +} + +static int crypto_pcbc_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct blkcipher_walk walk; + struct crypto_blkcipher *tfm = desc->tfm; + struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct crypto_cipher *child = ctx->child; + void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + if (walk.src.virt.addr == walk.dst.virt.addr) + nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, child, + xor); + else + nbytes = crypto_pcbc_encrypt_segment(desc, &walk, child, + xor); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_cipher *tfm, + void (*xor)(u8 *, const u8 *, + unsigned int)) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_decrypt; + int bsize = crypto_cipher_blocksize(tfm); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + u8 *iv = walk->iv; + + do { + fn(crypto_cipher_tfm(tfm), dst, src); + xor(dst, iv, bsize); + memcpy(iv, src, bsize); + xor(iv, dst, bsize); + + src += bsize; + dst += bsize; + } while ((nbytes -= bsize) >= bsize); + + memcpy(walk->iv, iv, bsize); + + return nbytes; +} + +static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_cipher *tfm, + void (*xor)(u8 *, const u8 *, + unsigned int)) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_decrypt; + int bsize = crypto_cipher_blocksize(tfm); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *iv = walk->iv; + u8 tmpbuf[bsize]; + + do { + memcpy(tmpbuf, src, bsize); + fn(crypto_cipher_tfm(tfm), src, src); + xor(src, iv, bsize); + memcpy(iv, tmpbuf, bsize); + xor(iv, src, bsize); + + src += bsize; + } while ((nbytes -= bsize) >= bsize); + + memcpy(walk->iv, iv, bsize); + + return nbytes; +} + +static int crypto_pcbc_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct blkcipher_walk walk; + struct crypto_blkcipher *tfm = desc->tfm; + struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct crypto_cipher *child = ctx->child; + void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + if (walk.src.virt.addr == walk.dst.virt.addr) + nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, child, + xor); + else + nbytes = crypto_pcbc_decrypt_segment(desc, &walk, child, + xor); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static void xor_byte(u8 *a, const u8 *b, unsigned int bs) +{ + do { + *a++ ^= *b++; + } while (--bs); +} + +static void xor_quad(u8 *dst, const u8 *src, unsigned int bs) +{ + u32 *a = (u32 *)dst; + u32 *b = (u32 *)src; + + do { + *a++ ^= *b++; + } while ((bs -= 4)); +} + +static void xor_64(u8 *a, const u8 *b, unsigned int bs) +{ + ((u32 *)a)[0] ^= ((u32 *)b)[0]; + ((u32 *)a)[1] ^= ((u32 *)b)[1]; +} + +static void xor_128(u8 *a, const u8 *b, unsigned int bs) +{ + ((u32 *)a)[0] ^= ((u32 *)b)[0]; + ((u32 *)a)[1] ^= ((u32 *)b)[1]; + ((u32 *)a)[2] ^= ((u32 *)b)[2]; + ((u32 *)a)[3] ^= ((u32 *)b)[3]; +} + +static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_spawn *spawn = crypto_instance_ctx(inst); + struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; + + switch (crypto_tfm_alg_blocksize(tfm)) { + case 8: + ctx->xor = xor_64; + break; + + case 16: + ctx->xor = xor_128; + break; + + default: + if (crypto_tfm_alg_blocksize(tfm) % 4) + ctx->xor = xor_byte; + else + ctx->xor = xor_quad; + } + + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + return 0; +} + +static void crypto_pcbc_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm); + crypto_free_cipher(ctx->child); +} + +static struct crypto_instance *crypto_pcbc_alloc(void *param, unsigned int len) +{ + struct crypto_instance *inst; + struct crypto_alg *alg; + + alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + if (IS_ERR(alg)) + return ERR_PTR(PTR_ERR(alg)); + + inst = crypto_alloc_instance("pcbc", alg); + if (IS_ERR(inst)) + goto out_put_alg; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = alg->cra_blocksize; + inst->alg.cra_alignmask = alg->cra_alignmask; + inst->alg.cra_type = &crypto_blkcipher_type; + + if (!(alg->cra_blocksize % 4)) + inst->alg.cra_alignmask |= 3; + inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize; + inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize; + inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize; + + inst->alg.cra_ctxsize = sizeof(struct crypto_pcbc_ctx); + + inst->alg.cra_init = crypto_pcbc_init_tfm; + inst->alg.cra_exit = crypto_pcbc_exit_tfm; + + inst->alg.cra_blkcipher.setkey = crypto_pcbc_setkey; + inst->alg.cra_blkcipher.encrypt = crypto_pcbc_encrypt; + inst->alg.cra_blkcipher.decrypt = crypto_pcbc_decrypt; + +out_put_alg: + crypto_mod_put(alg); + return inst; +} + +static void crypto_pcbc_free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_pcbc_tmpl = { + .name = "pcbc", + .alloc = crypto_pcbc_alloc, + .free = crypto_pcbc_free, + .module = THIS_MODULE, +}; + +static int __init crypto_pcbc_module_init(void) +{ + return crypto_register_template(&crypto_pcbc_tmpl); +} + +static void __exit crypto_pcbc_module_exit(void) +{ + crypto_unregister_template(&crypto_pcbc_tmpl); +} + +module_init(crypto_pcbc_module_init); +module_exit(crypto_pcbc_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PCBC block cipher algorithm"); diff --git a/trunk/crypto/tcrypt.c b/trunk/crypto/tcrypt.c index d671e8942b1f..f5e9da319ece 100644 --- a/trunk/crypto/tcrypt.c +++ b/trunk/crypto/tcrypt.c @@ -12,6 +12,7 @@ * Software Foundation; either version 2 of the License, or (at your option) * any later version. * + * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests * 2004-08-09 Added cipher speed tests (Reyk Floeter ) * 2003-09-14 Rewritten by Kartikey Mahendra Bhatt * @@ -71,7 +72,8 @@ static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", - "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", NULL + "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt", + "camellia", NULL }; static void hexdump(unsigned char *buf, unsigned int len) @@ -765,7 +767,7 @@ static void test_deflate(void) memcpy(tvmem, deflate_comp_tv_template, tsize); tv = (void *)tvmem; - tfm = crypto_alloc_tfm("deflate", 0); + tfm = crypto_alloc_comp("deflate", 0, CRYPTO_ALG_ASYNC); if (tfm == NULL) { printk("failed to load transform for deflate\n"); return; @@ -964,6 +966,26 @@ static void do_test(void) test_cipher("ecb(xeta)", DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS); + //FCrypt + test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template, + FCRYPT_ENC_TEST_VECTORS); + test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template, + FCRYPT_DEC_TEST_VECTORS); + + //CAMELLIA + test_cipher("ecb(camellia)", ENCRYPT, + camellia_enc_tv_template, + CAMELLIA_ENC_TEST_VECTORS); + test_cipher("ecb(camellia)", DECRYPT, + camellia_dec_tv_template, + CAMELLIA_DEC_TEST_VECTORS); + test_cipher("cbc(camellia)", ENCRYPT, + camellia_cbc_enc_tv_template, + CAMELLIA_CBC_ENC_TEST_VECTORS); + test_cipher("cbc(camellia)", DECRYPT, + camellia_cbc_dec_tv_template, + CAMELLIA_CBC_DEC_TEST_VECTORS); + test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); @@ -980,6 +1002,10 @@ static void do_test(void) HMAC_SHA1_TEST_VECTORS); test_hash("hmac(sha256)", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS); + test_hash("hmac(sha384)", hmac_sha384_tv_template, + HMAC_SHA384_TEST_VECTORS); + test_hash("hmac(sha512)", hmac_sha512_tv_template, + HMAC_SHA512_TEST_VECTORS); test_hash("xcbc(aes)", aes_xcbc128_tv_template, XCBC_AES_TEST_VECTORS); @@ -1177,6 +1203,28 @@ static void do_test(void) XETA_DEC_TEST_VECTORS); break; + case 31: + test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template, + FCRYPT_ENC_TEST_VECTORS); + test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template, + FCRYPT_DEC_TEST_VECTORS); + break; + + case 32: + test_cipher("ecb(camellia)", ENCRYPT, + camellia_enc_tv_template, + CAMELLIA_ENC_TEST_VECTORS); + test_cipher("ecb(camellia)", DECRYPT, + camellia_dec_tv_template, + CAMELLIA_DEC_TEST_VECTORS); + test_cipher("cbc(camellia)", ENCRYPT, + camellia_cbc_enc_tv_template, + CAMELLIA_CBC_ENC_TEST_VECTORS); + test_cipher("cbc(camellia)", DECRYPT, + camellia_cbc_dec_tv_template, + CAMELLIA_CBC_DEC_TEST_VECTORS); + break; + case 100: test_hash("hmac(md5)", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); @@ -1192,6 +1240,16 @@ static void do_test(void) HMAC_SHA256_TEST_VECTORS); break; + case 103: + test_hash("hmac(sha384)", hmac_sha384_tv_template, + HMAC_SHA384_TEST_VECTORS); + break; + + case 104: + test_hash("hmac(sha512)", hmac_sha512_tv_template, + HMAC_SHA512_TEST_VECTORS); + break; + case 200: test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0, @@ -1260,6 +1318,17 @@ static void do_test(void) des_speed_template); break; + case 205: + test_cipher_speed("ecb(camellia)", ENCRYPT, sec, NULL, 0, + camellia_speed_template); + test_cipher_speed("ecb(camellia)", DECRYPT, sec, NULL, 0, + camellia_speed_template); + test_cipher_speed("cbc(camellia)", ENCRYPT, sec, NULL, 0, + camellia_speed_template); + test_cipher_speed("cbc(camellia)", DECRYPT, sec, NULL, 0, + camellia_speed_template); + break; + case 300: /* fall through */ diff --git a/trunk/crypto/tcrypt.h b/trunk/crypto/tcrypt.h index 48a81362cb85..887527bd5bc6 100644 --- a/trunk/crypto/tcrypt.h +++ b/trunk/crypto/tcrypt.h @@ -12,6 +12,7 @@ * Software Foundation; either version 2 of the License, or (at your option) * any later version. * + * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests * 2004-08-09 Cipher speed tests by Reyk Floeter * 2003-09-14 Changes by Kartikey Mahendra Bhatt * @@ -27,7 +28,7 @@ struct hash_testvec { /* only used with keyed hash algorithms */ - char key[128] __attribute__ ((__aligned__(4))); + char key[132] __attribute__ ((__aligned__(4))); char plaintext[240]; char digest[MAX_DIGEST_SIZE]; unsigned char tap[MAX_TAP]; @@ -1001,6 +1002,248 @@ static struct hash_testvec aes_xcbc128_tv_template[] = { } }; +/* + * SHA384 HMAC test vectors from RFC4231 + */ + +#define HMAC_SHA384_TEST_VECTORS 4 + +static struct hash_testvec hmac_sha384_tv_template[] = { + { + .key = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b }, // (20 bytes) + .ksize = 20, + .plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 }, // ("Hi There") + .psize = 8, + .digest = { 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, + 0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f, + 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6, + 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, + 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f, + 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6 }, + }, { + .key = { 0x4a, 0x65, 0x66, 0x65 }, // ("Jefe") + .ksize = 4, + .plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, + 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, // ("what do ya want ") + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f }, // ("for nothing?") + .psize = 28, + .digest = { 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, + 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b, + 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47, + 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, + 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7, + 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49 }, + .np = 4, + .tap = { 7, 7, 7, 7 } + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, // (131 bytes) + .ksize = 131, + .plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, + 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, // ("Test Using Large") + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, // ("r Than Block-Siz") + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, // ("e Key - Hash Key") + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 }, // (" First") + .psize = 54, + .digest = { 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, + 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4, + 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f, + 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, + 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82, + 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52 }, + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, // (131 bytes) + .ksize = 131, + .plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, // ("This is a test u") + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, // ("sing a larger th") + 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, // ("an block-size ke") + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, + 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, // ("y and a larger t") + 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, // ("han block-size d") + 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, // ("ata. The key nee") + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, // ("ds to be hashed ") + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, // ("before being use") + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, // ("d by the HMAC al") + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e }, // ("gorithm.") + .psize = 152, + .digest = { 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, + 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c, + 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a, + 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, + 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d, + 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e }, + }, +}; + +/* + * SHA512 HMAC test vectors from RFC4231 + */ + +#define HMAC_SHA512_TEST_VECTORS 4 + +static struct hash_testvec hmac_sha512_tv_template[] = { + { + .key = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b }, // (20 bytes) + .ksize = 20, + .plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 }, // ("Hi There") + .psize = 8, + .digest = { 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, + 0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, + 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, + 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, + 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02, + 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, + 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, + 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54 }, + }, { + .key = { 0x4a, 0x65, 0x66, 0x65 }, // ("Jefe") + .ksize = 4, + .plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, + 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, // ("what do ya want ") + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f }, // ("for nothing?") + .psize = 28, + .digest = { 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, + 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3, + 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, + 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, + 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, 0x4a, + 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, + 0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b, + 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37 }, + .np = 4, + .tap = { 7, 7, 7, 7 } + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, // (131 bytes) + .ksize = 131, + .plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, + 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, // ("Test Using Large") + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, // ("r Than Block-Siz") + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, // ("e Key - Hash Key") + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 }, // (" First") + .psize = 54, + .digest = { 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, + 0xb7, 0x14, 0x93, 0xc1, 0xdd, 0x7b, 0xe8, 0xb4, + 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, + 0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, + 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, 0x98, + 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, + 0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec, + 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98 }, + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, // (131 bytes) + .ksize = 131, + .plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, // ("This is a test u") + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, // ("sing a larger th") + 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, // ("an block-size ke") + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, + 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, // ("y and a larger t") + 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, // ("han block-size d") + 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, // ("ata. The key nee") + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, // ("ds to be hashed ") + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, // ("before being use") + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, // ("d by the HMAC al") + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e }, // ("gorithm.") + .psize = 152, + .digest = { 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, + 0xa4, 0xdf, 0xa9, 0xf9, 0x6e, 0x5e, 0x3f, 0xfd, + 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, + 0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, + 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, 0xb1, + 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, + 0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60, + 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58 }, + }, +}; + /* * DES test vectors. */ @@ -3316,6 +3559,278 @@ static struct cipher_testvec xeta_dec_tv_template[] = { } }; +/* + * FCrypt test vectors + */ +#define FCRYPT_ENC_TEST_VECTORS ARRAY_SIZE(fcrypt_pcbc_enc_tv_template) +#define FCRYPT_DEC_TEST_VECTORS ARRAY_SIZE(fcrypt_pcbc_dec_tv_template) + +static struct cipher_testvec fcrypt_pcbc_enc_tv_template[] = { + { /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */ + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 8, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 8, + .result = { 0x0E, 0x09, 0x00, 0xC7, 0x3E, 0xF7, 0xED, 0x41 }, + .rlen = 8, + }, { + .key = { 0x11, 0x44, 0x77, 0xAA, 0xDD, 0x00, 0x33, 0x66 }, + .klen = 8, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 }, + .ilen = 8, + .result = { 0xD8, 0xED, 0x78, 0x74, 0x77, 0xEC, 0x06, 0x80 }, + .rlen = 8, + }, { /* From Arla */ + .key = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .klen = 8, + .iv = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .input = "The quick brown fox jumps over the lazy dogs.\0\0", + .ilen = 48, + .result = { 0x00, 0xf0, 0xe, 0x11, 0x75, 0xe6, 0x23, 0x82, + 0xee, 0xac, 0x98, 0x62, 0x44, 0x51, 0xe4, 0x84, + 0xc3, 0x59, 0xd8, 0xaa, 0x64, 0x60, 0xae, 0xf7, + 0xd2, 0xd9, 0x13, 0x79, 0x72, 0xa3, 0x45, 0x03, + 0x23, 0xb5, 0x62, 0xd7, 0x0c, 0xf5, 0x27, 0xd1, + 0xf8, 0x91, 0x3c, 0xac, 0x44, 0x22, 0x92, 0xef }, + .rlen = 48, + }, { + .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 8, + .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .input = "The quick brown fox jumps over the lazy dogs.\0\0", + .ilen = 48, + .result = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c, + 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d, + 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58, + 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0, + 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94, + 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f }, + .rlen = 48, + }, { /* split-page version */ + .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 8, + .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .input = "The quick brown fox jumps over the lazy dogs.\0\0", + .ilen = 48, + .result = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c, + 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d, + 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58, + 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0, + 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94, + 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f }, + .rlen = 48, + .np = 2, + .tap = { 20, 28 }, + } +}; + +static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = { + { /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */ + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 8, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x0E, 0x09, 0x00, 0xC7, 0x3E, 0xF7, 0xED, 0x41 }, + .ilen = 8, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rlen = 8, + }, { + .key = { 0x11, 0x44, 0x77, 0xAA, 0xDD, 0x00, 0x33, 0x66 }, + .klen = 8, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0xD8, 0xED, 0x78, 0x74, 0x77, 0xEC, 0x06, 0x80 }, + .ilen = 8, + .result = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 }, + .rlen = 8, + }, { /* From Arla */ + .key = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .klen = 8, + .iv = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .input = { 0x00, 0xf0, 0xe, 0x11, 0x75, 0xe6, 0x23, 0x82, + 0xee, 0xac, 0x98, 0x62, 0x44, 0x51, 0xe4, 0x84, + 0xc3, 0x59, 0xd8, 0xaa, 0x64, 0x60, 0xae, 0xf7, + 0xd2, 0xd9, 0x13, 0x79, 0x72, 0xa3, 0x45, 0x03, + 0x23, 0xb5, 0x62, 0xd7, 0x0c, 0xf5, 0x27, 0xd1, + 0xf8, 0x91, 0x3c, 0xac, 0x44, 0x22, 0x92, 0xef }, + .ilen = 48, + .result = "The quick brown fox jumps over the lazy dogs.\0\0", + .rlen = 48, + }, { + .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 8, + .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .input = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c, + 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d, + 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58, + 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0, + 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94, + 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f }, + .ilen = 48, + .result = "The quick brown fox jumps over the lazy dogs.\0\0", + .rlen = 48, + }, { /* split-page version */ + .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 8, + .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .input = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c, + 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d, + 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58, + 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0, + 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94, + 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f }, + .ilen = 48, + .result = "The quick brown fox jumps over the lazy dogs.\0\0", + .rlen = 48, + .np = 2, + .tap = { 20, 28 }, + } +}; + +/* + * CAMELLIA test vectors. + */ +#define CAMELLIA_ENC_TEST_VECTORS 3 +#define CAMELLIA_DEC_TEST_VECTORS 3 +#define CAMELLIA_CBC_ENC_TEST_VECTORS 2 +#define CAMELLIA_CBC_DEC_TEST_VECTORS 2 + +static struct cipher_testvec camellia_enc_tv_template[] = { + { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 16, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .ilen = 16, + .result = { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + .rlen = 16, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + .klen = 24, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .ilen = 16, + .result = { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + .rlen = 16, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + .klen = 32, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .ilen = 16, + .result = { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + .rlen = 16, + }, +}; + +static struct cipher_testvec camellia_dec_tv_template[] = { + { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 16, + .input = { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + .ilen = 16, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .rlen = 16, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + .klen = 24, + .input = { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + .ilen = 16, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .rlen = 16, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + .klen = 32, + .input = { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + .ilen = 16, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .rlen = 16, + }, +}; + +static struct cipher_testvec camellia_cbc_enc_tv_template[] = { + { + .key = { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, + 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 }, + .klen = 16, + .iv = { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, + 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 }, + .input = { "Single block msg" }, + .ilen = 16, + .result = { 0xea, 0x32, 0x12, 0x76, 0x3b, 0x50, 0x10, 0xe7, + 0x18, 0xf6, 0xfd, 0x5d, 0xf6, 0x8f, 0x13, 0x51 }, + .rlen = 16, + }, { + .key = { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, + 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a }, + .klen = 16, + .iv = { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, + 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 }, + .input = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .ilen = 32, + .result = { 0xa5, 0xdf, 0x6e, 0x50, 0xda, 0x70, 0x6c, 0x01, + 0x4a, 0xab, 0xf3, 0xf2, 0xd6, 0xfc, 0x6c, 0xfd, + 0x19, 0xb4, 0x3e, 0x57, 0x1c, 0x02, 0x5e, 0xa0, + 0x15, 0x78, 0xe0, 0x5e, 0xf2, 0xcb, 0x87, 0x16 }, + .rlen = 32, + }, +}; + +static struct cipher_testvec camellia_cbc_dec_tv_template[] = { + { + .key = { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, + 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 }, + .klen = 16, + .iv = { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, + 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 }, + .input = { 0xea, 0x32, 0x12, 0x76, 0x3b, 0x50, 0x10, 0xe7, + 0x18, 0xf6, 0xfd, 0x5d, 0xf6, 0x8f, 0x13, 0x51 }, + .ilen = 16, + .result = { "Single block msg" }, + .rlen = 16, + }, { + .key = { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, + 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a }, + .klen = 16, + .iv = { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, + 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 }, + .input = { 0xa5, 0xdf, 0x6e, 0x50, 0xda, 0x70, 0x6c, 0x01, + 0x4a, 0xab, 0xf3, 0xf2, 0xd6, 0xfc, 0x6c, 0xfd, + 0x19, 0xb4, 0x3e, 0x57, 0x1c, 0x02, 0x5e, 0xa0, + 0x15, 0x78, 0xe0, 0x5e, 0xf2, 0xcb, 0x87, 0x16 }, + .ilen = 32, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .rlen = 32, + }, +}; + /* * Compression stuff. */ @@ -3769,4 +4284,25 @@ static struct hash_speed generic_hash_speed_template[] = { { .blen = 0, .plen = 0, } }; +static struct cipher_speed camellia_speed_template[] = { + { .klen = 16, .blen = 16, }, + { .klen = 16, .blen = 64, }, + { .klen = 16, .blen = 256, }, + { .klen = 16, .blen = 1024, }, + { .klen = 16, .blen = 8192, }, + { .klen = 24, .blen = 16, }, + { .klen = 24, .blen = 64, }, + { .klen = 24, .blen = 256, }, + { .klen = 24, .blen = 1024, }, + { .klen = 24, .blen = 8192, }, + { .klen = 32, .blen = 16, }, + { .klen = 32, .blen = 64, }, + { .klen = 32, .blen = 256, }, + { .klen = 32, .blen = 1024, }, + { .klen = 32, .blen = 8192, }, + + /* End marker */ + { .klen = 0, .blen = 0, } +}; + #endif /* _CRYPTO_TCRYPT_H */ diff --git a/trunk/crypto/xcbc.c b/trunk/crypto/xcbc.c index 9347eb6bcf69..53e8ccbf0f5f 100644 --- a/trunk/crypto/xcbc.c +++ b/trunk/crypto/xcbc.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -47,7 +48,7 @@ static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101, * +------------------------ */ struct crypto_xcbc_ctx { - struct crypto_tfm *child; + struct crypto_cipher *child; u8 *odds; u8 *prev; u8 *key; @@ -75,8 +76,7 @@ static int _crypto_xcbc_digest_setkey(struct crypto_hash *parent, if ((err = crypto_cipher_setkey(ctx->child, ctx->key, ctx->keylen))) return err; - ctx->child->__crt_alg->cra_cipher.cia_encrypt(ctx->child, key1, - ctx->consts); + crypto_cipher_encrypt_one(ctx->child, key1, ctx->consts); return crypto_cipher_setkey(ctx->child, key1, bs); } @@ -86,7 +86,7 @@ static int crypto_xcbc_digest_setkey(struct crypto_hash *parent, { struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); - if (keylen != crypto_tfm_alg_blocksize(ctx->child)) + if (keylen != crypto_cipher_blocksize(ctx->child)) return -EINVAL; ctx->keylen = keylen; @@ -108,13 +108,13 @@ static int crypto_xcbc_digest_init(struct hash_desc *pdesc) return 0; } -static int crypto_xcbc_digest_update(struct hash_desc *pdesc, - struct scatterlist *sg, - unsigned int nbytes) +static int crypto_xcbc_digest_update2(struct hash_desc *pdesc, + struct scatterlist *sg, + unsigned int nbytes) { struct crypto_hash *parent = pdesc->tfm; struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); - struct crypto_tfm *tfm = ctx->child; + struct crypto_cipher *tfm = ctx->child; int bs = crypto_hash_blocksize(parent); unsigned int i = 0; @@ -142,7 +142,7 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc, offset += len; crypto_kunmap(p, 0); - crypto_yield(tfm->crt_flags); + crypto_yield(pdesc->flags); continue; } @@ -152,7 +152,7 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc, p += bs - ctx->len; ctx->xor(ctx->prev, ctx->odds, bs); - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, ctx->prev, ctx->prev); + crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); /* clearing the length */ ctx->len = 0; @@ -160,7 +160,8 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc, /* encrypting the rest of data */ while (len > bs) { ctx->xor(ctx->prev, p, bs); - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, ctx->prev, ctx->prev); + crypto_cipher_encrypt_one(tfm, ctx->prev, + ctx->prev); p += bs; len -= bs; } @@ -171,7 +172,7 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc, ctx->len = len; } crypto_kunmap(p, 0); - crypto_yield(tfm->crt_flags); + crypto_yield(pdesc->flags); slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset); offset = 0; pg++; @@ -183,11 +184,20 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc, return 0; } +static int crypto_xcbc_digest_update(struct hash_desc *pdesc, + struct scatterlist *sg, + unsigned int nbytes) +{ + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + return crypto_xcbc_digest_update2(pdesc, sg, nbytes); +} + static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) { struct crypto_hash *parent = pdesc->tfm; struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); - struct crypto_tfm *tfm = ctx->child; + struct crypto_cipher *tfm = ctx->child; int bs = crypto_hash_blocksize(parent); int err = 0; @@ -197,13 +207,14 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0) return err; - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, key2, (const u8*)(ctx->consts+bs)); + crypto_cipher_encrypt_one(tfm, key2, + (u8 *)(ctx->consts + bs)); ctx->xor(ctx->prev, ctx->odds, bs); ctx->xor(ctx->prev, key2, bs); _crypto_xcbc_digest_setkey(parent, ctx); - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, out, ctx->prev); + crypto_cipher_encrypt_one(tfm, out, ctx->prev); } else { u8 key3[bs]; unsigned int rlen; @@ -218,14 +229,15 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0) return err; - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, key3, (const u8*)(ctx->consts+bs*2)); + crypto_cipher_encrypt_one(tfm, key3, + (u8 *)(ctx->consts + bs * 2)); ctx->xor(ctx->prev, ctx->odds, bs); ctx->xor(ctx->prev, key3, bs); _crypto_xcbc_digest_setkey(parent, ctx); - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, out, ctx->prev); + crypto_cipher_encrypt_one(tfm, out, ctx->prev); } return 0; @@ -234,21 +246,25 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) static int crypto_xcbc_digest(struct hash_desc *pdesc, struct scatterlist *sg, unsigned int nbytes, u8 *out) { + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + crypto_xcbc_digest_init(pdesc); - crypto_xcbc_digest_update(pdesc, sg, nbytes); + crypto_xcbc_digest_update2(pdesc, sg, nbytes); return crypto_xcbc_digest_final(pdesc, out); } static int xcbc_init_tfm(struct crypto_tfm *tfm) { + struct crypto_cipher *cipher; struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm)); int bs = crypto_hash_blocksize(__crypto_hash_cast(tfm)); - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); switch(bs) { case 16: @@ -258,7 +274,7 @@ static int xcbc_init_tfm(struct crypto_tfm *tfm) return -EINVAL; } - ctx->child = crypto_cipher_cast(tfm); + ctx->child = cipher; ctx->odds = (u8*)(ctx+1); ctx->prev = ctx->odds + bs; ctx->key = ctx->prev + bs; diff --git a/trunk/drivers/Makefile b/trunk/drivers/Makefile index 0dd96d1afd39..f28dcb4ec8b3 100644 --- a/trunk/drivers/Makefile +++ b/trunk/drivers/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ mfd/ net/ media/ obj-$(CONFIG_NUBUS) += nubus/ obj-$(CONFIG_ATM) += atm/ -obj-$(CONFIG_PPC_PMAC) += macintosh/ +obj-y += macintosh/ obj-$(CONFIG_IDE) += ide/ obj-$(CONFIG_FC4) += fc4/ obj-$(CONFIG_SCSI) += scsi/ diff --git a/trunk/drivers/acpi/bay.c b/trunk/drivers/acpi/bay.c index 667fa1dfa1a3..91082ce6f5d1 100644 --- a/trunk/drivers/acpi/bay.c +++ b/trunk/drivers/acpi/bay.c @@ -296,7 +296,7 @@ static int bay_add(acpi_handle handle, int id) /* * Initialize bay device structure */ - new_bay = kzalloc(GFP_ATOMIC, sizeof(*new_bay)); + new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC); INIT_LIST_HEAD(&new_bay->list); new_bay->handle = handle; new_bay->name = (char *)nbuffer.pointer; diff --git a/trunk/drivers/ata/ahci.c b/trunk/drivers/ata/ahci.c index 48616c6fee9d..e2796fb40eb7 100644 --- a/trunk/drivers/ata/ahci.c +++ b/trunk/drivers/ata/ahci.c @@ -1173,7 +1173,7 @@ static void ahci_host_intr(struct ata_port *ap) * dangerous, we need to know more about them. Print * more of it. */ - const u32 *f = pp->rx_fis + RX_FIS_SDB; + const __le32 *f = pp->rx_fis + RX_FIS_SDB; ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ " "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n", diff --git a/trunk/drivers/ata/sata_svw.c b/trunk/drivers/ata/sata_svw.c index 46d8a94669b4..5f4e82ade6cd 100644 --- a/trunk/drivers/ata/sata_svw.c +++ b/trunk/drivers/ata/sata_svw.c @@ -116,7 +116,7 @@ static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -125,7 +125,7 @@ static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -262,7 +262,7 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) static u8 k2_stat_check_status(struct ata_port *ap) { - return readl((void *) ap->ioaddr.status_addr); + return readl((void __iomem *) ap->ioaddr.status_addr); } #ifdef CONFIG_PPC_OF diff --git a/trunk/drivers/char/watchdog/machzwd.c b/trunk/drivers/char/watchdog/machzwd.c index 276577d08fba..4d730fdbd528 100644 --- a/trunk/drivers/char/watchdog/machzwd.c +++ b/trunk/drivers/char/watchdog/machzwd.c @@ -325,7 +325,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return put_user(0, p); case WDIOC_KEEPALIVE: - zf_ping(0); + zf_ping(NULL); break; default: diff --git a/trunk/drivers/crypto/geode-aes.c b/trunk/drivers/crypto/geode-aes.c index 43a68398656f..31ea405f2eeb 100644 --- a/trunk/drivers/crypto/geode-aes.c +++ b/trunk/drivers/crypto/geode-aes.c @@ -457,7 +457,7 @@ static struct pci_driver geode_aes_driver = { static int __init geode_aes_init(void) { - return pci_module_init(&geode_aes_driver); + return pci_register_driver(&geode_aes_driver); } static void __exit diff --git a/trunk/drivers/hwmon/ams/ams-input.c b/trunk/drivers/hwmon/ams/ams-input.c index f126aa485134..18210164e307 100644 --- a/trunk/drivers/hwmon/ams/ams-input.c +++ b/trunk/drivers/hwmon/ams/ams-input.c @@ -153,7 +153,7 @@ int ams_input_init(void) } /* Call with ams_info.lock held! */ -void ams_input_exit() +void ams_input_exit(void) { ams_input_disable(); device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick); diff --git a/trunk/drivers/infiniband/ulp/iser/iser_initiator.c b/trunk/drivers/infiniband/ulp/iser/iser_initiator.c index 0a7d1ab60e6d..89e37283c836 100644 --- a/trunk/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/trunk/drivers/infiniband/ulp/iser/iser_initiator.c @@ -567,7 +567,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc, opcode = hdr->opcode & ISCSI_OPCODE_MASK; if (opcode == ISCSI_OP_SCSI_CMD_RSP) { - itt = hdr->itt & ISCSI_ITT_MASK; /* mask out cid and age bits */ + itt = get_itt(hdr->itt); /* mask out cid and age bits */ if (!(itt < session->cmds_max)) iser_err("itt can't be matched to task!!!" "conn %p opcode %d cmds_max %d itt %d\n", @@ -625,7 +625,7 @@ void iser_snd_completion(struct iser_desc *tx_desc) /* this arithmetic is legal by libiscsi dd_data allocation */ mtask = (void *) ((long)(void *)tx_desc - sizeof(struct iscsi_mgmt_task)); - if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) { + if (mtask->hdr->itt == RESERVED_ITT) { struct iscsi_session *session = conn->session; spin_lock(&conn->session->lock); diff --git a/trunk/drivers/input/touchscreen/ucb1400_ts.c b/trunk/drivers/input/touchscreen/ucb1400_ts.c index 4358a0a78eaa..c7db4032ef02 100644 --- a/trunk/drivers/input/touchscreen/ucb1400_ts.c +++ b/trunk/drivers/input/touchscreen/ucb1400_ts.c @@ -83,7 +83,7 @@ struct ucb1400 { - ac97_t *ac97; + struct snd_ac97 *ac97; struct input_dev *ts_idev; int irq; diff --git a/trunk/drivers/kvm/kvm_main.c b/trunk/drivers/kvm/kvm_main.c index b10972ed0c9f..099f0afd394d 100644 --- a/trunk/drivers/kvm/kvm_main.c +++ b/trunk/drivers/kvm/kvm_main.c @@ -62,7 +62,7 @@ static struct kvm_stats_debugfs_item { { "halt_exits", &kvm_stat.halt_exits }, { "request_irq", &kvm_stat.request_irq_exits }, { "irq_exits", &kvm_stat.irq_exits }, - { 0, 0 } + { NULL, NULL } }; static struct dentry *debugfs_dir; @@ -205,7 +205,7 @@ static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot) mutex_lock(&vcpu->mutex); if (unlikely(!vcpu->vmcs)) { mutex_unlock(&vcpu->mutex); - return 0; + return NULL; } return kvm_arch_ops->vcpu_load(vcpu); } @@ -257,9 +257,9 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free, if (!dont || free->dirty_bitmap != dont->dirty_bitmap) vfree(free->dirty_bitmap); - free->phys_mem = 0; + free->phys_mem = NULL; free->npages = 0; - free->dirty_bitmap = 0; + free->dirty_bitmap = NULL; } static void kvm_free_physmem(struct kvm *kvm) @@ -267,7 +267,7 @@ static void kvm_free_physmem(struct kvm *kvm) int i; for (i = 0; i < kvm->nmemslots; ++i) - kvm_free_physmem_slot(&kvm->memslots[i], 0); + kvm_free_physmem_slot(&kvm->memslots[i], NULL); } static void kvm_free_vcpu(struct kvm_vcpu *vcpu) @@ -640,11 +640,11 @@ static int kvm_dev_ioctl_set_memory_region(struct kvm *kvm, /* Deallocate if slot is being removed */ if (!npages) - new.phys_mem = 0; + new.phys_mem = NULL; /* Free page dirty bitmap if unneeded */ if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES)) - new.dirty_bitmap = 0; + new.dirty_bitmap = NULL; r = -ENOMEM; @@ -799,14 +799,14 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) && gfn < memslot->base_gfn + memslot->npages) return memslot; } - return 0; + return NULL; } EXPORT_SYMBOL_GPL(gfn_to_memslot); void mark_page_dirty(struct kvm *kvm, gfn_t gfn) { int i; - struct kvm_memory_slot *memslot = 0; + struct kvm_memory_slot *memslot = NULL; unsigned long rel_gfn; for (i = 0; i < kvm->nmemslots; ++i) { @@ -1778,6 +1778,7 @@ static long kvm_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct kvm *kvm = filp->private_data; + void __user *argp = (void __user *)arg; int r = -EINVAL; switch (ioctl) { @@ -1794,12 +1795,12 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_run kvm_run; r = -EFAULT; - if (copy_from_user(&kvm_run, (void *)arg, sizeof kvm_run)) + if (copy_from_user(&kvm_run, argp, sizeof kvm_run)) goto out; r = kvm_dev_ioctl_run(kvm, &kvm_run); if (r < 0 && r != -EINTR) goto out; - if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run)) { + if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) { r = -EFAULT; goto out; } @@ -1809,13 +1810,13 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_regs kvm_regs; r = -EFAULT; - if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs)) + if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) goto out; r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs); if (r) goto out; r = -EFAULT; - if (copy_to_user((void *)arg, &kvm_regs, sizeof kvm_regs)) + if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs)) goto out; r = 0; break; @@ -1824,7 +1825,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_regs kvm_regs; r = -EFAULT; - if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs)) + if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) goto out; r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs); if (r) @@ -1836,13 +1837,13 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_sregs kvm_sregs; r = -EFAULT; - if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs)) + if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) goto out; r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs); if (r) goto out; r = -EFAULT; - if (copy_to_user((void *)arg, &kvm_sregs, sizeof kvm_sregs)) + if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs)) goto out; r = 0; break; @@ -1851,7 +1852,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_sregs kvm_sregs; r = -EFAULT; - if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs)) + if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) goto out; r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs); if (r) @@ -1863,13 +1864,13 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_translation tr; r = -EFAULT; - if (copy_from_user(&tr, (void *)arg, sizeof tr)) + if (copy_from_user(&tr, argp, sizeof tr)) goto out; r = kvm_dev_ioctl_translate(kvm, &tr); if (r) goto out; r = -EFAULT; - if (copy_to_user((void *)arg, &tr, sizeof tr)) + if (copy_to_user(argp, &tr, sizeof tr)) goto out; r = 0; break; @@ -1878,7 +1879,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_interrupt irq; r = -EFAULT; - if (copy_from_user(&irq, (void *)arg, sizeof irq)) + if (copy_from_user(&irq, argp, sizeof irq)) goto out; r = kvm_dev_ioctl_interrupt(kvm, &irq); if (r) @@ -1890,7 +1891,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_debug_guest dbg; r = -EFAULT; - if (copy_from_user(&dbg, (void *)arg, sizeof dbg)) + if (copy_from_user(&dbg, argp, sizeof dbg)) goto out; r = kvm_dev_ioctl_debug_guest(kvm, &dbg); if (r) @@ -1902,7 +1903,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_memory_region kvm_mem; r = -EFAULT; - if (copy_from_user(&kvm_mem, (void *)arg, sizeof kvm_mem)) + if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) goto out; r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem); if (r) @@ -1913,7 +1914,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_dirty_log log; r = -EFAULT; - if (copy_from_user(&log, (void *)arg, sizeof log)) + if (copy_from_user(&log, argp, sizeof log)) goto out; r = kvm_dev_ioctl_get_dirty_log(kvm, &log); if (r) @@ -1921,13 +1922,13 @@ static long kvm_dev_ioctl(struct file *filp, break; } case KVM_GET_MSRS: - r = msr_io(kvm, (void __user *)arg, get_msr, 1); + r = msr_io(kvm, argp, get_msr, 1); break; case KVM_SET_MSRS: - r = msr_io(kvm, (void __user *)arg, do_set_msr, 0); + r = msr_io(kvm, argp, do_set_msr, 0); break; case KVM_GET_MSR_INDEX_LIST: { - struct kvm_msr_list __user *user_msr_list = (void __user *)arg; + struct kvm_msr_list __user *user_msr_list = argp; struct kvm_msr_list msr_list; unsigned n; @@ -2014,7 +2015,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val, * in vmx root mode. */ printk(KERN_INFO "kvm: exiting hardware virtualization\n"); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); } return NOTIFY_OK; } @@ -2028,7 +2029,7 @@ static __init void kvm_init_debug(void) { struct kvm_stats_debugfs_item *p; - debugfs_dir = debugfs_create_dir("kvm", 0); + debugfs_dir = debugfs_create_dir("kvm", NULL); for (p = debugfs_entries; p->name; ++p) p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir, p->data); @@ -2069,7 +2070,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) if (r < 0) return r; - on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1); register_reboot_notifier(&kvm_reboot_notifier); kvm_chardev_ops.owner = module; @@ -2084,7 +2085,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) out_free: unregister_reboot_notifier(&kvm_reboot_notifier); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); kvm_arch_ops->hardware_unsetup(); return r; } @@ -2094,7 +2095,7 @@ void kvm_exit_arch(void) misc_deregister(&kvm_dev); unregister_reboot_notifier(&kvm_reboot_notifier); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); kvm_arch_ops->hardware_unsetup(); kvm_arch_ops = NULL; } diff --git a/trunk/drivers/kvm/mmu.c b/trunk/drivers/kvm/mmu.c index 22c426cd8cb2..be793770f31b 100644 --- a/trunk/drivers/kvm/mmu.c +++ b/trunk/drivers/kvm/mmu.c @@ -333,7 +333,7 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu, for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j) ; desc->shadow_ptes[i] = desc->shadow_ptes[j]; - desc->shadow_ptes[j] = 0; + desc->shadow_ptes[j] = NULL; if (j != 0) return; if (!prev_desc && !desc->more) diff --git a/trunk/drivers/kvm/svm.c b/trunk/drivers/kvm/svm.c index c79df79307ed..85f61dd1e936 100644 --- a/trunk/drivers/kvm/svm.c +++ b/trunk/drivers/kvm/svm.c @@ -274,7 +274,7 @@ static void svm_hardware_disable(void *garbage) wrmsrl(MSR_VM_HSAVE_PA, 0); rdmsrl(MSR_EFER, efer); wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); - per_cpu(svm_data, raw_smp_processor_id()) = 0; + per_cpu(svm_data, raw_smp_processor_id()) = NULL; __free_page(svm_data->save_area); kfree(svm_data); } @@ -642,7 +642,7 @@ static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg) case VCPU_SREG_LDTR: return &save->ldtr; } BUG(); - return 0; + return NULL; } static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg) @@ -934,7 +934,7 @@ static int io_get_override(struct kvm_vcpu *vcpu, return 0; *addr_override = 0; - *seg = 0; + *seg = NULL; for (i = 0; i < ins_length; i++) switch (inst[i]) { case 0xf0: @@ -1087,7 +1087,7 @@ static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - if (emulate_instruction(vcpu, 0, 0, 0) != EMULATE_DONE) + if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE) printk(KERN_ERR "%s: failed\n", __FUNCTION__); return 1; } diff --git a/trunk/drivers/kvm/vmx.c b/trunk/drivers/kvm/vmx.c index 54c35c0b3181..27e05a77e21a 100644 --- a/trunk/drivers/kvm/vmx.c +++ b/trunk/drivers/kvm/vmx.c @@ -98,7 +98,7 @@ static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr) for (i = 0; i < vcpu->nmsrs; ++i) if (vcpu->guest_msrs[i].index == msr) return &vcpu->guest_msrs[i]; - return 0; + return NULL; } static void vmcs_clear(struct vmcs *vmcs) diff --git a/trunk/drivers/macintosh/Kconfig b/trunk/drivers/macintosh/Kconfig index a9e747c39791..1a86387e23be 100644 --- a/trunk/drivers/macintosh/Kconfig +++ b/trunk/drivers/macintosh/Kconfig @@ -1,6 +1,6 @@ menu "Macintosh device drivers" - depends on PPC || MAC + depends on PPC || MAC || X86 config ADB bool "Apple Desktop Bus (ADB) support" diff --git a/trunk/drivers/macintosh/rack-meter.c b/trunk/drivers/macintosh/rack-meter.c index 5ed41fe84e57..f83fad2a3ff4 100644 --- a/trunk/drivers/macintosh/rack-meter.c +++ b/trunk/drivers/macintosh/rack-meter.c @@ -171,11 +171,11 @@ static void rackmeter_setup_dbdma(struct rackmeter *rm) /* Make sure dbdma is reset */ DBDMA_DO_RESET(rm->dma_regs); - pr_debug("rackmeter: mark offset=0x%lx\n", + pr_debug("rackmeter: mark offset=0x%zx\n", offsetof(struct rackmeter_dma, mark)); - pr_debug("rackmeter: buf1 offset=0x%lx\n", + pr_debug("rackmeter: buf1 offset=0x%zx\n", offsetof(struct rackmeter_dma, buf1)); - pr_debug("rackmeter: buf2 offset=0x%lx\n", + pr_debug("rackmeter: buf2 offset=0x%zx\n", offsetof(struct rackmeter_dma, buf2)); /* Prepare 4 dbdma commands for the 2 buffers */ diff --git a/trunk/drivers/md/bitmap.c b/trunk/drivers/md/bitmap.c index 11108165e264..059704fbb753 100644 --- a/trunk/drivers/md/bitmap.c +++ b/trunk/drivers/md/bitmap.c @@ -1160,6 +1160,22 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect return 0; } + if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) { + DEFINE_WAIT(__wait); + /* note that it is safe to do the prepare_to_wait + * after the test as long as we do it before dropping + * the spinlock. + */ + prepare_to_wait(&bitmap->overflow_wait, &__wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&bitmap->lock); + bitmap->mddev->queue + ->unplug_fn(bitmap->mddev->queue); + schedule(); + finish_wait(&bitmap->overflow_wait, &__wait); + continue; + } + switch(*bmc) { case 0: bitmap_file_set_bit(bitmap, offset); @@ -1169,7 +1185,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect case 1: *bmc = 2; } - BUG_ON((*bmc & COUNTER_MAX) == COUNTER_MAX); + (*bmc)++; spin_unlock_irq(&bitmap->lock); @@ -1207,6 +1223,9 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto if (!success && ! (*bmc & NEEDED_MASK)) *bmc |= NEEDED_MASK; + if ((*bmc & COUNTER_MAX) == COUNTER_MAX) + wake_up(&bitmap->overflow_wait); + (*bmc)--; if (*bmc <= 2) { set_page_attr(bitmap, @@ -1431,6 +1450,7 @@ int bitmap_create(mddev_t *mddev) spin_lock_init(&bitmap->lock); atomic_set(&bitmap->pending_writes, 0); init_waitqueue_head(&bitmap->write_wait); + init_waitqueue_head(&bitmap->overflow_wait); bitmap->mddev = mddev; diff --git a/trunk/drivers/md/raid5.c b/trunk/drivers/md/raid5.c index 467c16982d02..11c3d7bfa797 100644 --- a/trunk/drivers/md/raid5.c +++ b/trunk/drivers/md/raid5.c @@ -2620,7 +2620,7 @@ static struct bio *remove_bio_from_retry(raid5_conf_t *conf) } bi = conf->retry_read_aligned_list; if(bi) { - conf->retry_read_aligned = bi->bi_next; + conf->retry_read_aligned_list = bi->bi_next; bi->bi_next = NULL; bi->bi_phys_segments = 1; /* biased count of active stripes */ bi->bi_hw_segments = 0; /* count of processed stripes */ @@ -2669,6 +2669,27 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error) return 0; } +static int bio_fits_rdev(struct bio *bi) +{ + request_queue_t *q = bdev_get_queue(bi->bi_bdev); + + if ((bi->bi_size>>9) > q->max_sectors) + return 0; + blk_recount_segments(q, bi); + if (bi->bi_phys_segments > q->max_phys_segments || + bi->bi_hw_segments > q->max_hw_segments) + return 0; + + if (q->merge_bvec_fn) + /* it's too hard to apply the merge_bvec_fn at this stage, + * just just give up + */ + return 0; + + return 1; +} + + static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio) { mddev_t *mddev = q->queuedata; @@ -2715,6 +2736,13 @@ static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio) align_bi->bi_flags &= ~(1 << BIO_SEG_VALID); align_bi->bi_sector += rdev->data_offset; + if (!bio_fits_rdev(align_bi)) { + /* too big in some way */ + bio_put(align_bi); + rdev_dec_pending(rdev, mddev); + return 0; + } + spin_lock_irq(&conf->device_lock); wait_event_lock_irq(conf->wait_for_stripe, conf->quiesce == 0, @@ -3107,7 +3135,9 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio) last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9); for (; logical_sector < last_sector; - logical_sector += STRIPE_SECTORS, scnt++) { + logical_sector += STRIPE_SECTORS, + sector += STRIPE_SECTORS, + scnt++) { if (scnt < raid_bio->bi_hw_segments) /* already done this stripe */ @@ -3123,7 +3153,13 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio) } set_bit(R5_ReadError, &sh->dev[dd_idx].flags); - add_stripe_bio(sh, raid_bio, dd_idx, 0); + if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) { + release_stripe(sh); + raid_bio->bi_hw_segments = scnt; + conf->retry_read_aligned = raid_bio; + return handled; + } + handle_stripe(sh, NULL); release_stripe(sh); handled++; diff --git a/trunk/drivers/media/common/ir-keymaps.c b/trunk/drivers/media/common/ir-keymaps.c index f51e02fe3655..0e948a5c5a03 100644 --- a/trunk/drivers/media/common/ir-keymaps.c +++ b/trunk/drivers/media/common/ir-keymaps.c @@ -698,7 +698,6 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = { [ 0x29 ] = KEY_TEXT, [ 0x2a ] = KEY_MEDIA, [ 0x18 ] = KEY_EPG, - [ 0x27 ] = KEY_RECORD, }; EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey); diff --git a/trunk/drivers/media/video/usbvision/usbvision-video.c b/trunk/drivers/media/video/usbvision/usbvision-video.c index 7243337b771a..bdd6301d2a47 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-video.c +++ b/trunk/drivers/media/video/usbvision/usbvision-video.c @@ -1072,7 +1072,7 @@ static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file, } -static ssize_t usbvision_v4l2_read(struct file *file, char *buf, +static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *dev = video_devdata(file); diff --git a/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig index 89bba277da5f..bedae4ad3f74 100644 --- a/trunk/drivers/misc/Kconfig +++ b/trunk/drivers/misc/Kconfig @@ -42,7 +42,7 @@ config SGI_IOC4 config TIFM_CORE tristate "TI Flash Media interface support (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && PCI help If you want support for Texas Instruments(R) Flash Media adapters you should select this option and then also choose an appropriate diff --git a/trunk/drivers/misc/lkdtm.c b/trunk/drivers/misc/lkdtm.c index db9d7df75ae0..552b7957a92a 100644 --- a/trunk/drivers/misc/lkdtm.c +++ b/trunk/drivers/misc/lkdtm.c @@ -108,8 +108,8 @@ static struct jprobe lkdtm; static int lkdtm_parse_commandline(void); static void lkdtm_handler(void); -static char* cpoint_name = INVALID; -static char* cpoint_type = NONE; +static char* cpoint_name; +static char* cpoint_type; static int cpoint_count = DEFAULT_COUNT; static int recur_count = REC_NUM_DEFAULT; diff --git a/trunk/drivers/mmc/Kconfig b/trunk/drivers/mmc/Kconfig index 4224686fdf2a..12af9c718764 100644 --- a/trunk/drivers/mmc/Kconfig +++ b/trunk/drivers/mmc/Kconfig @@ -111,7 +111,7 @@ config MMC_IMX config MMC_TIFM_SD tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" - depends on MMC && EXPERIMENTAL + depends on MMC && EXPERIMENTAL && PCI select TIFM_CORE help Say Y here if you want to be able to access MMC/SD cards with diff --git a/trunk/drivers/net/3c503.c b/trunk/drivers/net/3c503.c index 7e34c4f07b70..bc7e906571d3 100644 --- a/trunk/drivers/net/3c503.c +++ b/trunk/drivers/net/3c503.c @@ -600,8 +600,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring count -= semi_count; memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, base + ring_offset, count, 0); + memcpy_fromio(skb->data, base + ring_offset, count); } return; } diff --git a/trunk/drivers/net/Kconfig b/trunk/drivers/net/Kconfig index ad92b6a76ee6..38f41a593b12 100644 --- a/trunk/drivers/net/Kconfig +++ b/trunk/drivers/net/Kconfig @@ -2335,6 +2335,17 @@ config QLA3XXX To compile this driver as a module, choose M here: the module will be called qla3xxx. +config ATL1 + tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + select CRC32 + select MII + help + This driver supports the Attansic L1 gigabit ethernet adapter. + + To compile this driver as a module, choose M here. The module + will be called atl1. + endmenu # @@ -2534,7 +2545,7 @@ config RIONET_RX_SIZE config FDDI bool "FDDI driver support" - depends on (PCI || EISA) + depends on (PCI || EISA || TC) help Fiber Distributed Data Interface is a high speed local area network design; essentially a replacement for high speed Ethernet. FDDI can @@ -2544,11 +2555,31 @@ config FDDI will say N. config DEFXX - tristate "Digital DEFEA and DEFPA adapter support" - depends on FDDI && (PCI || EISA) - help - This is support for the DIGITAL series of EISA (DEFEA) and PCI - (DEFPA) controllers which can connect you to a local FDDI network. + tristate "Digital DEFTA/DEFEA/DEFPA adapter support" + depends on FDDI && (PCI || EISA || TC) + ---help--- + This is support for the DIGITAL series of TURBOchannel (DEFTA), + EISA (DEFEA) and PCI (DEFPA) controllers which can connect you + to a local FDDI network. + + To compile this driver as a module, choose M here: the module + will be called defxx. If unsure, say N. + +config DEFXX_MMIO + bool + prompt "Use MMIO instead of PIO" if PCI || EISA + depends on DEFXX + default n if PCI || EISA + default y + ---help--- + This instructs the driver to use EISA or PCI memory-mapped I/O + (MMIO) as appropriate instead of programmed I/O ports (PIO). + Enabling this gives an improvement in processing time in parts + of the driver, but it may cause problems with EISA (DEFEA) + adapters. TURBOchannel does not have the concept of I/O ports, + so MMIO is always used for these (DEFTA) adapters. + + If unsure, say N. config SKFP tristate "SysKonnect FDDI PCI support" diff --git a/trunk/drivers/net/Makefile b/trunk/drivers/net/Makefile index 0878e3df5174..33af833667da 100644 --- a/trunk/drivers/net/Makefile +++ b/trunk/drivers/net/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_BONDING) += bonding/ +obj-$(CONFIG_ATL1) += atl1/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o gianfar_driver-objs := gianfar.o \ diff --git a/trunk/drivers/net/ac3200.c b/trunk/drivers/net/ac3200.c index c01f87f5bed7..644c408515df 100644 --- a/trunk/drivers/net/ac3200.c +++ b/trunk/drivers/net/ac3200.c @@ -327,8 +327,7 @@ static void ac_block_input(struct net_device *dev, int count, struct sk_buff *sk memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES*256, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, start, count, 0); + memcpy_fromio(skb->data, start, count); } } diff --git a/trunk/drivers/net/atl1/Makefile b/trunk/drivers/net/atl1/Makefile new file mode 100644 index 000000000000..a6b707e4e69e --- /dev/null +++ b/trunk/drivers/net/atl1/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ATL1) += atl1.o +atl1-y += atl1_main.o atl1_hw.o atl1_ethtool.o atl1_param.o diff --git a/trunk/drivers/net/atl1/atl1.h b/trunk/drivers/net/atl1/atl1.h new file mode 100644 index 000000000000..b1c6034e68fa --- /dev/null +++ b/trunk/drivers/net/atl1/atl1.h @@ -0,0 +1,283 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * 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 _ATL1_H_ +#define _ATL1_H_ + +#include +#include + +#include "atl1_hw.h" + +/* function prototypes needed by multiple files */ +s32 atl1_up(struct atl1_adapter *adapter); +void atl1_down(struct atl1_adapter *adapter); +int atl1_reset(struct atl1_adapter *adapter); +s32 atl1_setup_ring_resources(struct atl1_adapter *adapter); +void atl1_free_ring_resources(struct atl1_adapter *adapter); + +extern char atl1_driver_name[]; +extern char atl1_driver_version[]; +extern const struct ethtool_ops atl1_ethtool_ops; + +struct atl1_adapter; + +#define ATL1_MAX_INTR 3 + +#define ATL1_DEFAULT_TPD 256 +#define ATL1_MAX_TPD 1024 +#define ATL1_MIN_TPD 64 +#define ATL1_DEFAULT_RFD 512 +#define ATL1_MIN_RFD 128 +#define ATL1_MAX_RFD 2048 + +#define ATL1_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i])) +#define ATL1_RFD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_free_desc) +#define ATL1_TPD_DESC(R, i) ATL1_GET_DESC(R, i, struct tx_packet_desc) +#define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc) + +/* + * Some workarounds require millisecond delays and are run during interrupt + * context. Most notably, when establishing link, the phy may need tweaking + * but cannot process phy register reads/writes faster than millisecond + * intervals...and we establish link due to a "link status change" interrupt. + */ + +/* + * wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer + */ +struct atl1_buffer { + struct sk_buff *skb; + u16 length; + u16 alloced; + dma_addr_t dma; +}; + +#define MAX_TX_BUF_LEN 0x3000 /* 12KB */ + +struct atl1_tpd_ring { + void *desc; /* pointer to the descriptor ring memory */ + dma_addr_t dma; /* physical adress of the descriptor ring */ + u16 size; /* length of descriptor ring in bytes */ + u16 count; /* number of descriptors in the ring */ + u16 hw_idx; /* hardware index */ + atomic_t next_to_clean; + atomic_t next_to_use; + struct atl1_buffer *buffer_info; +}; + +struct atl1_rfd_ring { + void *desc; + dma_addr_t dma; + u16 size; + u16 count; + atomic_t next_to_use; + u16 next_to_clean; + struct atl1_buffer *buffer_info; +}; + +struct atl1_rrd_ring { + void *desc; + dma_addr_t dma; + unsigned int size; + u16 count; + u16 next_to_use; + atomic_t next_to_clean; +}; + +struct atl1_ring_header { + void *desc; /* pointer to the descriptor ring memory */ + dma_addr_t dma; /* physical adress of the descriptor ring */ + unsigned int size; /* length of descriptor ring in bytes */ +}; + +struct atl1_cmb { + struct coals_msg_block *cmb; + dma_addr_t dma; +}; + +struct atl1_smb { + struct stats_msg_block *smb; + dma_addr_t dma; +}; + +/* Statistics counters */ +struct atl1_sft_stats { + u64 rx_packets; + u64 tx_packets; + u64 rx_bytes; + u64 tx_bytes; + u64 multicast; + u64 collisions; + u64 rx_errors; + u64 rx_length_errors; + u64 rx_crc_errors; + u64 rx_frame_errors; + u64 rx_fifo_errors; + u64 rx_missed_errors; + u64 tx_errors; + u64 tx_fifo_errors; + u64 tx_aborted_errors; + u64 tx_window_errors; + u64 tx_carrier_errors; + + u64 tx_pause; /* num Pause packet transmitted. */ + u64 excecol; /* num tx packets aborted due to excessive collisions. */ + u64 deffer; /* num deferred tx packets */ + u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */ + u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */ + u64 latecol; /* num tx packets w/ late collisions. */ + u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ + u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */ + u64 rx_pause; /* num Pause packets received. */ + u64 rx_rrd_ov; + u64 rx_trunc; +}; + +/* board specific private data structure */ +#define ATL1_REGS_LEN 8 + +/* Structure containing variables used by the shared code */ +struct atl1_hw { + u8 __iomem *hw_addr; + struct atl1_adapter *back; + enum atl1_dma_order dma_ord; + enum atl1_dma_rcb rcb_value; + enum atl1_dma_req_block dmar_block; + enum atl1_dma_req_block dmaw_block; + u8 preamble_len; + u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */ + u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */ + u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */ + u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */ + u8 ipgr1; /* 64bit Carrier-Sense window */ + u8 ipgr2; /* 96-bit IPG window */ + u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */ + u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */ + u8 rfd_fetch_gap; + u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */ + u8 tpd_fetch_th; + u8 tpd_fetch_gap; + u16 tx_jumbo_task_th; + u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is + 8 bytes long */ + u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */ + u16 rx_jumbo_lkah; + u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */ + u16 lcol; /* Collision Window */ + + u16 cmb_tpd; + u16 cmb_rrd; + u16 cmb_rx_timer; + u16 cmb_tx_timer; + u32 smb_timer; + u16 media_type; + u16 autoneg_advertised; + u16 pci_cmd_word; + + u16 mii_autoneg_adv_reg; + u16 mii_1000t_ctrl_reg; + + u32 mem_rang; + u32 txcw; + u32 max_frame_size; + u32 min_frame_size; + u32 mc_filter_type; + u32 num_mc_addrs; + u32 collision_delta; + u32 tx_packet_delta; + u16 phy_spd_default; + + u16 dev_rev; + u8 revision_id; + + /* spi flash */ + u8 flash_vendor; + + u8 dma_fairness; + u8 mac_addr[ETH_ALEN]; + u8 perm_mac_addr[ETH_ALEN]; + + /* bool phy_preamble_sup; */ + bool phy_configured; +}; + +struct atl1_adapter { + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + struct atl1_sft_stats soft_stats; + + struct vlan_group *vlgrp; + u32 rx_buffer_len; + u32 wol; + u16 link_speed; + u16 link_duplex; + spinlock_t lock; + atomic_t irq_sem; + struct work_struct tx_timeout_task; + struct work_struct link_chg_task; + struct work_struct pcie_dma_to_rst_task; + struct timer_list watchdog_timer; + struct timer_list phy_config_timer; + bool phy_timer_pending; + + bool mac_disabled; + + /* All descriptor rings' memory */ + struct atl1_ring_header ring_header; + + /* TX */ + struct atl1_tpd_ring tpd_ring; + spinlock_t mb_lock; + + /* RX */ + struct atl1_rfd_ring rfd_ring; + struct atl1_rrd_ring rrd_ring; + u64 hw_csum_err; + u64 hw_csum_good; + + u32 gorcl; + u64 gorcl_old; + + /* Interrupt Moderator timer ( 2us resolution) */ + u16 imt; + /* Interrupt Clear timer (2us resolution) */ + u16 ict; + + /* MII interface info */ + struct mii_if_info mii; + + /* structs defined in atl1_hw.h */ + u32 bd_number; /* board number */ + bool pci_using_64; + struct atl1_hw hw; + struct atl1_smb smb; + struct atl1_cmb cmb; + + u32 pci_state[16]; +}; + +#endif /* _ATL1_H_ */ diff --git a/trunk/drivers/net/atl1/atl1_ethtool.c b/trunk/drivers/net/atl1/atl1_ethtool.c new file mode 100644 index 000000000000..c11c27798e5c --- /dev/null +++ b/trunk/drivers/net/atl1/atl1_ethtool.c @@ -0,0 +1,508 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include + +#include "atl1.h" + +struct atl1_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \ + offsetof(struct atl1_adapter, m) + +static struct atl1_stats atl1_gstrings_stats[] = { + {"rx_packets", ATL1_STAT(soft_stats.rx_packets)}, + {"tx_packets", ATL1_STAT(soft_stats.tx_packets)}, + {"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)}, + {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)}, + {"rx_errors", ATL1_STAT(soft_stats.rx_errors)}, + {"tx_errors", ATL1_STAT(soft_stats.tx_errors)}, + {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)}, + {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)}, + {"multicast", ATL1_STAT(soft_stats.multicast)}, + {"collisions", ATL1_STAT(soft_stats.collisions)}, + {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)}, + {"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, + {"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)}, + {"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)}, + {"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)}, + {"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, + {"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)}, + {"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)}, + {"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)}, + {"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)}, + {"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)}, + {"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)}, + {"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)}, + {"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)}, + {"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)}, + {"tx_underun", ATL1_STAT(soft_stats.tx_underun)}, + {"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)}, + {"tx_pause", ATL1_STAT(soft_stats.tx_pause)}, + {"rx_pause", ATL1_STAT(soft_stats.rx_pause)}, + {"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)}, + {"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)} +}; + +static void atl1_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int i; + char *p; + + for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { + p = (char *)adapter+atl1_gstrings_stats[i].stat_offset; + data[i] = (atl1_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } + +} + +static int atl1_get_stats_count(struct net_device *netdev) +{ + return ARRAY_SIZE(atl1_gstrings_stats); +} + +static int atl1_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_TP); + ecmd->advertising = ADVERTISED_TP; + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + ecmd->advertising |= ADVERTISED_Autoneg; + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) { + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->advertising |= + (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full); + } + else + ecmd->advertising |= (ADVERTISED_1000baseT_Full); + } + ecmd->port = PORT_TP; + ecmd->phy_address = 0; + ecmd->transceiver = XCVR_INTERNAL; + + if (netif_carrier_ok(adapter->netdev)) { + u16 link_speed, link_duplex; + atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex); + ecmd->speed = link_speed; + if (link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + ecmd->autoneg = AUTONEG_ENABLE; + else + ecmd->autoneg = AUTONEG_DISABLE; + + return 0; +} + +static int atl1_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + u16 phy_data; + int ret_val = 0; + u16 old_media_type = hw->media_type; + + if (netif_running(adapter->netdev)) { + printk(KERN_DEBUG "%s: ethtool shutting down adapter\n", + atl1_driver_name); + atl1_down(adapter); + } + + if (ecmd->autoneg == AUTONEG_ENABLE) + hw->media_type = MEDIA_TYPE_AUTO_SENSOR; + else { + if (ecmd->speed == SPEED_1000) { + if (ecmd->duplex != DUPLEX_FULL) { + printk(KERN_WARNING + "%s: can't force to 1000M half duplex\n", + atl1_driver_name); + ret_val = -EINVAL; + goto exit_sset; + } + hw->media_type = MEDIA_TYPE_1000M_FULL; + } else if (ecmd->speed == SPEED_100) { + if (ecmd->duplex == DUPLEX_FULL) { + hw->media_type = MEDIA_TYPE_100M_FULL; + } else + hw->media_type = MEDIA_TYPE_100M_HALF; + } else { + if (ecmd->duplex == DUPLEX_FULL) + hw->media_type = MEDIA_TYPE_10M_FULL; + else + hw->media_type = MEDIA_TYPE_10M_HALF; + } + } + switch (hw->media_type) { + case MEDIA_TYPE_AUTO_SENSOR: + ecmd->advertising = + ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_TP; + break; + case MEDIA_TYPE_1000M_FULL: + ecmd->advertising = + ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_TP; + break; + default: + ecmd->advertising = 0; + break; + } + if (atl1_phy_setup_autoneg_adv(hw)) { + ret_val = -EINVAL; + printk(KERN_WARNING + "%s: invalid ethtool speed/duplex setting\n", + atl1_driver_name); + goto exit_sset; + } + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); +exit_sset: + if (ret_val) + hw->media_type = old_media_type; + + if (netif_running(adapter->netdev)) { + printk(KERN_DEBUG "%s: ethtool starting adapter\n", + atl1_driver_name); + atl1_up(adapter); + } else if (!ret_val) { + printk(KERN_DEBUG "%s: ethtool resetting adapter\n", + atl1_driver_name); + atl1_reset(adapter); + } + return ret_val; +} + +static void atl1_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver)); + strncpy(drvinfo->version, atl1_driver_version, + sizeof(drvinfo->version)); + strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), + sizeof(drvinfo->bus_info)); + drvinfo->eedump_len = ATL1_EEDUMP_LEN; +} + +static void atl1_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; + wol->wolopts = 0; + if (adapter->wol & ATL1_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & ATL1_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & ATL1_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & ATL1_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + return; +} + +static int atl1_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + adapter->wol = 0; + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= ATL1_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= ATL1_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= ATL1_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= ATL1_WUFC_MAG; + return 0; +} + +static void atl1_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_tpd_ring *txdr = &adapter->tpd_ring; + struct atl1_rfd_ring *rxdr = &adapter->rfd_ring; + + ring->rx_max_pending = ATL1_MAX_RFD; + ring->tx_max_pending = ATL1_MAX_TPD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rxdr->count; + ring->tx_pending = txdr->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int atl1_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_tpd_ring *tpdr = &adapter->tpd_ring; + struct atl1_rrd_ring *rrdr = &adapter->rrd_ring; + struct atl1_rfd_ring *rfdr = &adapter->rfd_ring; + + struct atl1_tpd_ring tpd_old, tpd_new; + struct atl1_rfd_ring rfd_old, rfd_new; + struct atl1_rrd_ring rrd_old, rrd_new; + struct atl1_ring_header rhdr_old, rhdr_new; + int err; + + tpd_old = adapter->tpd_ring; + rfd_old = adapter->rfd_ring; + rrd_old = adapter->rrd_ring; + rhdr_old = adapter->ring_header; + + if (netif_running(adapter->netdev)) + atl1_down(adapter); + + rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD); + rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD : + rfdr->count; + rfdr->count = (rfdr->count + 3) & ~3; + rrdr->count = rfdr->count; + + tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD); + tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD : + tpdr->count; + tpdr->count = (tpdr->count + 3) & ~3; + + if (netif_running(adapter->netdev)) { + /* try to get new resources before deleting old */ + err = atl1_setup_ring_resources(adapter); + if (err) + goto err_setup_ring; + + /* + * save the new, restore the old in order to free it, + * then restore the new back again + */ + + rfd_new = adapter->rfd_ring; + rrd_new = adapter->rrd_ring; + tpd_new = adapter->tpd_ring; + rhdr_new = adapter->ring_header; + adapter->rfd_ring = rfd_old; + adapter->rrd_ring = rrd_old; + adapter->tpd_ring = tpd_old; + adapter->ring_header = rhdr_old; + atl1_free_ring_resources(adapter); + adapter->rfd_ring = rfd_new; + adapter->rrd_ring = rrd_new; + adapter->tpd_ring = tpd_new; + adapter->ring_header = rhdr_new; + + err = atl1_up(adapter); + if (err) + return err; + } + return 0; + +err_setup_ring: + adapter->rfd_ring = rfd_old; + adapter->rrd_ring = rrd_old; + adapter->tpd_ring = tpd_old; + adapter->ring_header = rhdr_old; + atl1_up(adapter); + return err; +} + +static void atl1_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *epause) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + epause->autoneg = AUTONEG_ENABLE; + } else { + epause->autoneg = AUTONEG_DISABLE; + } + epause->rx_pause = 1; + epause->tx_pause = 1; +} + +static int atl1_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *epause) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + epause->autoneg = AUTONEG_ENABLE; + } else { + epause->autoneg = AUTONEG_DISABLE; + } + + epause->rx_pause = 1; + epause->tx_pause = 1; + + return 0; +} + +static u32 atl1_get_rx_csum(struct net_device *netdev) +{ + return 1; +} + +static void atl1_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { + memcpy(p, atl1_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int atl1_nway_reset(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (netif_running(netdev)) { + u16 phy_data; + atl1_down(adapter); + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + } else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = MII_CR_FULL_DUPLEX | + MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = MII_CR_FULL_DUPLEX | + MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + } + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); + atl1_up(adapter); + } + return 0; +} + +const struct ethtool_ops atl1_ethtool_ops = { + .get_settings = atl1_get_settings, + .set_settings = atl1_set_settings, + .get_drvinfo = atl1_get_drvinfo, + .get_wol = atl1_get_wol, + .set_wol = atl1_set_wol, + .get_ringparam = atl1_get_ringparam, + .set_ringparam = atl1_set_ringparam, + .get_pauseparam = atl1_get_pauseparam, + .set_pauseparam = atl1_set_pauseparam, + .get_rx_csum = atl1_get_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_hw_csum, + .get_link = ethtool_op_get_link, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_strings = atl1_get_strings, + .nway_reset = atl1_nway_reset, + .get_ethtool_stats = atl1_get_ethtool_stats, + .get_stats_count = atl1_get_stats_count, + .get_tso = ethtool_op_get_tso, + .set_tso = ethtool_op_set_tso, +}; diff --git a/trunk/drivers/net/atl1/atl1_hw.c b/trunk/drivers/net/atl1/atl1_hw.c new file mode 100644 index 000000000000..08b2d785469d --- /dev/null +++ b/trunk/drivers/net/atl1/atl1_hw.c @@ -0,0 +1,718 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "atl1.h" + +/* + * Reset the transmit and receive units; mask and clear all interrupts. + * hw - Struct containing variables accessed by shared code + * return : ATL1_SUCCESS or idle status (if error) + */ +s32 atl1_reset_hw(struct atl1_hw *hw) +{ + u32 icr; + int i; + + /* + * Clear Interrupt mask to stop board from generating + * interrupts & Clear any pending interrupt events + */ + /* + * iowrite32(0, hw->hw_addr + REG_IMR); + * iowrite32(0xffffffff, hw->hw_addr + REG_ISR); + */ + + /* + * Issue Soft Reset to the MAC. This will reset the chip's + * transmit, receive, DMA. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + iowrite32(MASTER_CTRL_SOFT_RST, hw->hw_addr + REG_MASTER_CTRL); + ioread32(hw->hw_addr + REG_MASTER_CTRL); + + iowrite16(1, hw->hw_addr + REG_GPHY_ENABLE); + ioread16(hw->hw_addr + REG_GPHY_ENABLE); + + msleep(1); /* delay about 1ms */ + + /* Wait at least 10ms for All module to be Idle */ + for (i = 0; i < 10; i++) { + icr = ioread32(hw->hw_addr + REG_IDLE_STATUS); + if (!icr) + break; + msleep(1); /* delay 1 ms */ + cpu_relax(); /* FIXME: is this still the right way to do this? */ + } + + if (icr) { + printk (KERN_DEBUG "icr = %x\n", icr); + return icr; + } + + return ATL1_SUCCESS; +} + +/* function about EEPROM + * + * check_eeprom_exist + * return 0 if eeprom exist + */ +static int atl1_check_eeprom_exist(struct atl1_hw *hw) +{ + u32 value; + value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + if (value & SPI_FLASH_CTRL_EN_VPD) { + value &= ~SPI_FLASH_CTRL_EN_VPD; + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + } + + value = ioread16(hw->hw_addr + REG_PCIE_CAP_LIST); + return ((value & 0xFF00) == 0x6C00) ? 0 : 1; +} + +static bool atl1_read_eeprom(struct atl1_hw *hw, u32 offset, u32 *p_value) +{ + int i; + u32 control; + + if (offset & 3) + return false; /* address do not align */ + + iowrite32(0, hw->hw_addr + REG_VPD_DATA); + control = (offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT; + iowrite32(control, hw->hw_addr + REG_VPD_CAP); + ioread32(hw->hw_addr + REG_VPD_CAP); + + for (i = 0; i < 10; i++) { + msleep(2); + control = ioread32(hw->hw_addr + REG_VPD_CAP); + if (control & VPD_CAP_VPD_FLAG) + break; + } + if (control & VPD_CAP_VPD_FLAG) { + *p_value = ioread32(hw->hw_addr + REG_VPD_DATA); + return true; + } + return false; /* timeout */ +} + +/* + * Reads the value from a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to read + */ +s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data) +{ + u32 val; + int i; + + val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | + MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 << + MDIO_CLK_SEL_SHIFT; + iowrite32(val, hw->hw_addr + REG_MDIO_CTRL); + ioread32(hw->hw_addr + REG_MDIO_CTRL); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + if (!(val & (MDIO_START | MDIO_BUSY))) { + *phy_data = (u16) val; + return ATL1_SUCCESS; + } + return ATL1_ERR_PHY; +} + +#define CUSTOM_SPI_CS_SETUP 2 +#define CUSTOM_SPI_CLK_HI 2 +#define CUSTOM_SPI_CLK_LO 2 +#define CUSTOM_SPI_CS_HOLD 2 +#define CUSTOM_SPI_CS_HI 3 + +static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf) +{ + int i; + u32 value; + + iowrite32(0, hw->hw_addr + REG_SPI_DATA); + iowrite32(addr, hw->hw_addr + REG_SPI_ADDR); + + value = SPI_FLASH_CTRL_WAIT_READY | + (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) << + SPI_FLASH_CTRL_CS_SETUP_SHIFT | (CUSTOM_SPI_CLK_HI & + SPI_FLASH_CTRL_CLK_HI_MASK) << + SPI_FLASH_CTRL_CLK_HI_SHIFT | (CUSTOM_SPI_CLK_LO & + SPI_FLASH_CTRL_CLK_LO_MASK) << + SPI_FLASH_CTRL_CLK_LO_SHIFT | (CUSTOM_SPI_CS_HOLD & + SPI_FLASH_CTRL_CS_HOLD_MASK) << + SPI_FLASH_CTRL_CS_HOLD_SHIFT | (CUSTOM_SPI_CS_HI & + SPI_FLASH_CTRL_CS_HI_MASK) << + SPI_FLASH_CTRL_CS_HI_SHIFT | (1 & SPI_FLASH_CTRL_INS_MASK) << + SPI_FLASH_CTRL_INS_SHIFT; + + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + + value |= SPI_FLASH_CTRL_START; + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + + for (i = 0; i < 10; i++) { + msleep(1); /* 1ms */ + value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + if (!(value & SPI_FLASH_CTRL_START)) + break; + } + + if (value & SPI_FLASH_CTRL_START) + return false; + + *buf = ioread32(hw->hw_addr + REG_SPI_DATA); + + return true; +} + +/* + * get_permanent_address + * return 0 if get valid mac address, + */ +static int atl1_get_permanent_address(struct atl1_hw *hw) +{ + u32 addr[2]; + u32 i, control; + u16 reg; + u8 eth_addr[ETH_ALEN]; + bool key_valid; + + if (is_valid_ether_addr(hw->perm_mac_addr)) + return 0; + + /* init */ + addr[0] = addr[1] = 0; + + if (!atl1_check_eeprom_exist(hw)) { /* eeprom exist */ + reg = 0; + key_valid = false; + /* Read out all EEPROM content */ + i = 0; + while (1) { + if (atl1_read_eeprom(hw, i + 0x100, &control)) { + if (key_valid) { + if (reg == REG_MAC_STA_ADDR) + addr[0] = control; + else if (reg == (REG_MAC_STA_ADDR + 4)) + addr[1] = control; + key_valid = false; + } else if ((control & 0xff) == 0x5A) { + key_valid = true; + reg = (u16) (control >> 16); + } else + break; /* assume data end while encount an invalid KEYWORD */ + } else + break; /* read error */ + i += 4; + } + +/* + * The following 2 lines are the Attansic originals. Saving for posterity. + * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); + * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); + */ + *(u32 *) & eth_addr[2] = swab32(addr[0]); + *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; + } + + /* see if SPI FLAGS exist ? */ + addr[0] = addr[1] = 0; + reg = 0; + key_valid = false; + i = 0; + while (1) { + if (atl1_spi_read(hw, i + 0x1f000, &control)) { + if (key_valid) { + if (reg == REG_MAC_STA_ADDR) + addr[0] = control; + else if (reg == (REG_MAC_STA_ADDR + 4)) + addr[1] = control; + key_valid = false; + } else if ((control & 0xff) == 0x5A) { + key_valid = true; + reg = (u16) (control >> 16); + } else + break; /* data end */ + } else + break; /* read error */ + i += 4; + } + +/* + * The following 2 lines are the Attansic originals. Saving for posterity. + * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); + * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); + */ + *(u32 *) & eth_addr[2] = swab32(addr[0]); + *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; +} + +/* + * Reads the adapter's MAC address from the EEPROM + * hw - Struct containing variables accessed by shared code + */ +s32 atl1_read_mac_addr(struct atl1_hw *hw) +{ + u16 i; + + if (atl1_get_permanent_address(hw)) + random_ether_addr(hw->perm_mac_addr); + + for (i = 0; i < ETH_ALEN; i++) + hw->mac_addr[i] = hw->perm_mac_addr[i]; + return ATL1_SUCCESS; +} + +/* + * Hashes an address to determine its location in the multicast table + * hw - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + * + * atl1_hash_mc_addr + * purpose + * set hash value for a multicast address + * hash calcu processing : + * 1. calcu 32bit CRC for multicast address + * 2. reverse crc with MSB to LSB + */ +u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr) +{ + u32 crc32, value = 0; + int i; + + crc32 = ether_crc_le(6, mc_addr); + crc32 = ~crc32; + for (i = 0; i < 32; i++) + value |= (((crc32 >> i) & 1) << (31 - i)); + + return value; +} + +/* + * Sets the bit in the multicast table corresponding to the hash value. + * hw - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + */ +void atl1_hash_set(struct atl1_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg; + u32 mta; + + /* + * The HASH Table is a register array of 2 32-bit registers. + * It is treated like an array of 64 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 31) & 0x1; + hash_bit = (hash_value >> 26) & 0x1F; + mta = ioread32((hw + REG_RX_HASH_TABLE) + (hash_reg << 2)); + mta |= (1 << hash_bit); + iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2)); +} + +/* + * Writes a value to a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to write + * data - data to write to the PHY + */ +s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data) +{ + int i; + u32 val; + + val = ((u32) (phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | + (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | + MDIO_SUP_PREAMBLE | + MDIO_START | MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; + iowrite32(val, hw->hw_addr + REG_MDIO_CTRL); + ioread32(hw->hw_addr + REG_MDIO_CTRL); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if (!(val & (MDIO_START | MDIO_BUSY))) + return ATL1_SUCCESS; + + return ATL1_ERR_PHY; +} + +/* + * Make L001's PHY out of Power Saving State (bug) + * hw - Struct containing variables accessed by shared code + * when power on, L001's PHY always on Power saving State + * (Gigabit Link forbidden) + */ +static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw) +{ + s32 ret; + ret = atl1_write_phy_reg(hw, 29, 0x0029); + if (ret) + return ret; + return atl1_write_phy_reg(hw, 30, 0); +} + +/* + *TODO: do something or get rid of this + */ +s32 atl1_phy_enter_power_saving(struct atl1_hw *hw) +{ +/* s32 ret_val; + * u16 phy_data; + */ + +/* + ret_val = atl1_write_phy_reg(hw, ...); + ret_val = atl1_write_phy_reg(hw, ...); + .... +*/ + return ATL1_SUCCESS; +} + +/* + * Resets the PHY and make all config validate + * hw - Struct containing variables accessed by shared code + * + * Sets bit 15 and 12 of the MII Control regiser (for F001 bug) + */ +static s32 atl1_phy_reset(struct atl1_hw *hw) +{ + s32 ret_val; + u16 phy_data; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + } + + ret_val = atl1_write_phy_reg(hw, MII_BMCR, phy_data); + if (ret_val) { + u32 val; + int i; + /* pcie serdes link may be down! */ + printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n", + atl1_driver_name); + + for (i = 0; i < 25; i++) { + msleep(1); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if ((val & (MDIO_START | MDIO_BUSY)) != 0) { + printk(KERN_WARNING + "%s: pcie link down at least for 25ms\n", + atl1_driver_name); + return ret_val; + } + } + return ATL1_SUCCESS; +} + +/* + * Configures PHY autoneg and flow control advertisement settings + * hw - Struct containing variables accessed by shared code + */ +s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw) +{ + s32 ret_val; + s16 mii_autoneg_adv_reg; + s16 mii_1000t_ctrl_reg; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK; + + /* Read the MII 1000Base-T Control Register (Address 9). */ + mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK; + + /* + * First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK; + mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK; + + /* + * Need to parse media_type and set up + * the appropriate PHY registers. + */ + switch (hw->media_type) { + case MEDIA_TYPE_AUTO_SENSOR: + mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS | + MII_AR_10T_FD_CAPS | + MII_AR_100TX_HD_CAPS | + MII_AR_100TX_FD_CAPS); + mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS; + break; + + case MEDIA_TYPE_1000M_FULL: + mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS; + break; + + case MEDIA_TYPE_100M_FULL: + mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS; + break; + + case MEDIA_TYPE_100M_HALF: + mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS; + break; + + case MEDIA_TYPE_10M_FULL: + mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS; + break; + + default: + mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS; + break; + } + + /* flow control fixed to enable all */ + mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE); + + hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; + hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg; + + ret_val = atl1_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + ret_val = atl1_write_phy_reg(hw, MII_AT001_CR, mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + + return ATL1_SUCCESS; +} + +/* + * Configures link settings. + * hw - Struct containing variables accessed by shared code + * Assumes the hardware has previously been reset and the + * transmitter and receiver are not enabled. + */ +static s32 atl1_setup_link(struct atl1_hw *hw) +{ + s32 ret_val; + + /* + * Options: + * PHY will advertise value(s) parsed from + * autoneg_advertised and fc + * no matter what autoneg is , We will not wait link result. + */ + ret_val = atl1_phy_setup_autoneg_adv(hw); + if (ret_val) { + printk(KERN_DEBUG "%s: error setting up autonegotiation\n", + atl1_driver_name); + return ret_val; + } + /* SW.Reset , En-Auto-Neg if needed */ + ret_val = atl1_phy_reset(hw); + if (ret_val) { + printk(KERN_DEBUG "%s: error resetting the phy\n", + atl1_driver_name); + return ret_val; + } + hw->phy_configured = true; + return ret_val; +} + +static struct atl1_spi_flash_dev flash_table[] = { +/* MFR_NAME WRSR READ PRGM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */ + {"Atmel", 0x00, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62}, + {"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60}, + {"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7}, +}; + +static void atl1_init_flash_opcode(struct atl1_hw *hw) +{ + if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0])) + hw->flash_vendor = 0; /* ATMEL */ + + /* Init OP table */ + iowrite8(flash_table[hw->flash_vendor].cmd_program, + hw->hw_addr + REG_SPI_FLASH_OP_PROGRAM); + iowrite8(flash_table[hw->flash_vendor].cmd_sector_erase, + hw->hw_addr + REG_SPI_FLASH_OP_SC_ERASE); + iowrite8(flash_table[hw->flash_vendor].cmd_chip_erase, + hw->hw_addr + REG_SPI_FLASH_OP_CHIP_ERASE); + iowrite8(flash_table[hw->flash_vendor].cmd_rdid, + hw->hw_addr + REG_SPI_FLASH_OP_RDID); + iowrite8(flash_table[hw->flash_vendor].cmd_wren, + hw->hw_addr + REG_SPI_FLASH_OP_WREN); + iowrite8(flash_table[hw->flash_vendor].cmd_rdsr, + hw->hw_addr + REG_SPI_FLASH_OP_RDSR); + iowrite8(flash_table[hw->flash_vendor].cmd_wrsr, + hw->hw_addr + REG_SPI_FLASH_OP_WRSR); + iowrite8(flash_table[hw->flash_vendor].cmd_read, + hw->hw_addr + REG_SPI_FLASH_OP_READ); +} + +/* + * Performs basic configuration of the adapter. + * hw - Struct containing variables accessed by shared code + * Assumes that the controller has previously been reset and is in a + * post-reset uninitialized state. Initializes multicast table, + * and Calls routines to setup link + * Leaves the transmit and receive units disabled and uninitialized. + */ +s32 atl1_init_hw(struct atl1_hw *hw) +{ + u32 ret_val = 0; + + /* Zero out the Multicast HASH table */ + iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE); + /* clear the old settings from the multicast hash table */ + iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2)); + + atl1_init_flash_opcode(hw); + + if (!hw->phy_configured) { + /* enable GPHY LinkChange Interrrupt */ + ret_val = atl1_write_phy_reg(hw, 18, 0xC00); + if (ret_val) + return ret_val; + /* make PHY out of power-saving state */ + ret_val = atl1_phy_leave_power_saving(hw); + if (ret_val) + return ret_val; + /* Call a subroutine to configure the link */ + ret_val = atl1_setup_link(hw); + } + return ret_val; +} + +/* + * Detects the current speed and duplex settings of the hardware. + * hw - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + */ +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex) +{ + s32 ret_val; + u16 phy_data; + + /* ; --- Read PHY Specific Status Register (17) */ + ret_val = atl1_read_phy_reg(hw, MII_AT001_PSSR, &phy_data); + if (ret_val) + return ret_val; + + if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED)) + return ATL1_ERR_PHY_RES; + + switch (phy_data & MII_AT001_PSSR_SPEED) { + case MII_AT001_PSSR_1000MBS: + *speed = SPEED_1000; + break; + case MII_AT001_PSSR_100MBS: + *speed = SPEED_100; + break; + case MII_AT001_PSSR_10MBS: + *speed = SPEED_10; + break; + default: + printk(KERN_DEBUG "%s: error getting speed\n", + atl1_driver_name); + return ATL1_ERR_PHY_SPEED; + break; + } + if (phy_data & MII_AT001_PSSR_DPLX) + *duplex = FULL_DUPLEX; + else + *duplex = HALF_DUPLEX; + + return ATL1_SUCCESS; +} + +void atl1_set_mac_addr(struct atl1_hw *hw) +{ + u32 value; + /* + * 00-0B-6A-F6-00-DC + * 0: 6AF600DC 1: 000B + * low dword + */ + value = (((u32) hw->mac_addr[2]) << 24) | + (((u32) hw->mac_addr[3]) << 16) | + (((u32) hw->mac_addr[4]) << 8) | (((u32) hw->mac_addr[5])); + iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR); + /* high dword */ + value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1])); + iowrite32(value, (hw->hw_addr + REG_MAC_STA_ADDR) + (1 << 2)); +} diff --git a/trunk/drivers/net/atl1/atl1_hw.h b/trunk/drivers/net/atl1/atl1_hw.h new file mode 100644 index 000000000000..100c09c66e64 --- /dev/null +++ b/trunk/drivers/net/atl1/atl1_hw.h @@ -0,0 +1,951 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * 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. + * + * There are a lot of defines in here that are unused and/or have cryptic + * names. Please leave them alone, as they're the closest thing we have + * to a spec from Attansic at present. *ahem* -- CHS + */ + +#ifndef _ATL1_HW_H_ +#define _ATL1_HW_H_ + +#include +#include + +struct atl1_adapter; +struct atl1_hw; + +/* function prototypes needed by multiple files */ +s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw); +s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data); +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex); +s32 atl1_read_mac_addr(struct atl1_hw *hw); +s32 atl1_init_hw(struct atl1_hw *hw); +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex); +s32 atl1_set_speed_and_duplex(struct atl1_hw *hw, u16 speed, u16 duplex); +u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr); +void atl1_hash_set(struct atl1_hw *hw, u32 hash_value); +s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data); +void atl1_set_mac_addr(struct atl1_hw *hw); +s32 atl1_phy_enter_power_saving(struct atl1_hw *hw); +s32 atl1_reset_hw(struct atl1_hw *hw); +void atl1_check_options(struct atl1_adapter *adapter); + +/* register definitions */ +#define REG_PCIE_CAP_LIST 0x58 + +#define REG_VPD_CAP 0x6C +#define VPD_CAP_ID_MASK 0xff +#define VPD_CAP_ID_SHIFT 0 +#define VPD_CAP_NEXT_PTR_MASK 0xFF +#define VPD_CAP_NEXT_PTR_SHIFT 8 +#define VPD_CAP_VPD_ADDR_MASK 0x7FFF +#define VPD_CAP_VPD_ADDR_SHIFT 16 +#define VPD_CAP_VPD_FLAG 0x80000000 + +#define REG_VPD_DATA 0x70 + +#define REG_SPI_FLASH_CTRL 0x200 +#define SPI_FLASH_CTRL_STS_NON_RDY 0x1 +#define SPI_FLASH_CTRL_STS_WEN 0x2 +#define SPI_FLASH_CTRL_STS_WPEN 0x80 +#define SPI_FLASH_CTRL_DEV_STS_MASK 0xFF +#define SPI_FLASH_CTRL_DEV_STS_SHIFT 0 +#define SPI_FLASH_CTRL_INS_MASK 0x7 +#define SPI_FLASH_CTRL_INS_SHIFT 8 +#define SPI_FLASH_CTRL_START 0x800 +#define SPI_FLASH_CTRL_EN_VPD 0x2000 +#define SPI_FLASH_CTRL_LDSTART 0x8000 +#define SPI_FLASH_CTRL_CS_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HI_SHIFT 16 +#define SPI_FLASH_CTRL_CS_HOLD_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HOLD_SHIFT 18 +#define SPI_FLASH_CTRL_CLK_LO_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_LO_SHIFT 20 +#define SPI_FLASH_CTRL_CLK_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_HI_SHIFT 22 +#define SPI_FLASH_CTRL_CS_SETUP_MASK 0x3 +#define SPI_FLASH_CTRL_CS_SETUP_SHIFT 24 +#define SPI_FLASH_CTRL_EROM_PGSZ_MASK 0x3 +#define SPI_FLASH_CTRL_EROM_PGSZ_SHIFT 26 +#define SPI_FLASH_CTRL_WAIT_READY 0x10000000 + +#define REG_SPI_ADDR 0x204 + +#define REG_SPI_DATA 0x208 + +#define REG_SPI_FLASH_CONFIG 0x20C +#define SPI_FLASH_CONFIG_LD_ADDR_MASK 0xFFFFFF +#define SPI_FLASH_CONFIG_LD_ADDR_SHIFT 0 +#define SPI_FLASH_CONFIG_VPD_ADDR_MASK 0x3 +#define SPI_FLASH_CONFIG_VPD_ADDR_SHIFT 24 +#define SPI_FLASH_CONFIG_LD_EXIST 0x4000000 + +#define REG_SPI_FLASH_OP_PROGRAM 0x210 +#define REG_SPI_FLASH_OP_SC_ERASE 0x211 +#define REG_SPI_FLASH_OP_CHIP_ERASE 0x212 +#define REG_SPI_FLASH_OP_RDID 0x213 +#define REG_SPI_FLASH_OP_WREN 0x214 +#define REG_SPI_FLASH_OP_RDSR 0x215 +#define REG_SPI_FLASH_OP_WRSR 0x216 +#define REG_SPI_FLASH_OP_READ 0x217 + +#define REG_TWSI_CTRL 0x218 +#define TWSI_CTRL_LD_OFFSET_MASK 0xFF +#define TWSI_CTRL_LD_OFFSET_SHIFT 0 +#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7 +#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8 +#define TWSI_CTRL_SW_LDSTART 0x800 +#define TWSI_CTRL_HW_LDSTART 0x1000 +#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F +#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15 +#define TWSI_CTRL_LD_EXIST 0x400000 +#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23 +#define TWSI_CTRL_FREQ_SEL_100K 0 +#define TWSI_CTRL_FREQ_SEL_200K 1 +#define TWSI_CTRL_FREQ_SEL_300K 2 +#define TWSI_CTRL_FREQ_SEL_400K 3 +#define TWSI_CTRL_SMB_SLV_ADDR +#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24 + +#define REG_PCIE_DEV_MISC_CTRL 0x21C +#define PCIE_DEV_MISC_CTRL_EXT_PIPE 0x2 +#define PCIE_DEV_MISC_CTRL_RETRY_BUFDIS 0x1 +#define PCIE_DEV_MISC_CTRL_SPIROM_EXIST 0x4 +#define PCIE_DEV_MISC_CTRL_SERDES_ENDIAN 0x8 +#define PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN 0x10 + +/* Selene Master Control Register */ +#define REG_MASTER_CTRL 0x1400 +#define MASTER_CTRL_SOFT_RST 0x1 +#define MASTER_CTRL_MTIMER_EN 0x2 +#define MASTER_CTRL_ITIMER_EN 0x4 +#define MASTER_CTRL_MANUAL_INT 0x8 +#define MASTER_CTRL_REV_NUM_SHIFT 16 +#define MASTER_CTRL_REV_NUM_MASK 0xff +#define MASTER_CTRL_DEV_ID_SHIFT 24 +#define MASTER_CTRL_DEV_ID_MASK 0xff + +/* Timer Initial Value Register */ +#define REG_MANUAL_TIMER_INIT 0x1404 + +/* IRQ ModeratorTimer Initial Value Register */ +#define REG_IRQ_MODU_TIMER_INIT 0x1408 + +#define REG_GPHY_ENABLE 0x140C + +/* IRQ Anti-Lost Timer Initial Value Register */ +#define REG_CMBDISDMA_TIMER 0x140E + +/* Block IDLE Status Register */ +#define REG_IDLE_STATUS 0x1410 +#define IDLE_STATUS_RXMAC 1 +#define IDLE_STATUS_TXMAC 2 +#define IDLE_STATUS_RXQ 4 +#define IDLE_STATUS_TXQ 8 +#define IDLE_STATUS_DMAR 0x10 +#define IDLE_STATUS_DMAW 0x20 +#define IDLE_STATUS_SMB 0x40 +#define IDLE_STATUS_CMB 0x80 + +/* MDIO Control Register */ +#define REG_MDIO_CTRL 0x1414 +#define MDIO_DATA_MASK 0xffff +#define MDIO_DATA_SHIFT 0 +#define MDIO_REG_ADDR_MASK 0x1f +#define MDIO_REG_ADDR_SHIFT 16 +#define MDIO_RW 0x200000 +#define MDIO_SUP_PREAMBLE 0x400000 +#define MDIO_START 0x800000 +#define MDIO_CLK_SEL_SHIFT 24 +#define MDIO_CLK_25_4 0 +#define MDIO_CLK_25_6 2 +#define MDIO_CLK_25_8 3 +#define MDIO_CLK_25_10 4 +#define MDIO_CLK_25_14 5 +#define MDIO_CLK_25_20 6 +#define MDIO_CLK_25_28 7 +#define MDIO_BUSY 0x8000000 +#define MDIO_WAIT_TIMES 30 + +/* MII PHY Status Register */ +#define REG_PHY_STATUS 0x1418 + +/* BIST Control and Status Register0 (for the Packet Memory) */ +#define REG_BIST0_CTRL 0x141c +#define BIST0_NOW 0x1 +#define BIST0_SRAM_FAIL 0x2 +#define BIST0_FUSE_FLAG 0x4 +#define REG_BIST1_CTRL 0x1420 +#define BIST1_NOW 0x1 +#define BIST1_SRAM_FAIL 0x2 +#define BIST1_FUSE_FLAG 0x4 + +/* MAC Control Register */ +#define REG_MAC_CTRL 0x1480 +#define MAC_CTRL_TX_EN 1 +#define MAC_CTRL_RX_EN 2 +#define MAC_CTRL_TX_FLOW 4 +#define MAC_CTRL_RX_FLOW 8 +#define MAC_CTRL_LOOPBACK 0x10 +#define MAC_CTRL_DUPLX 0x20 +#define MAC_CTRL_ADD_CRC 0x40 +#define MAC_CTRL_PAD 0x80 +#define MAC_CTRL_LENCHK 0x100 +#define MAC_CTRL_HUGE_EN 0x200 +#define MAC_CTRL_PRMLEN_SHIFT 10 +#define MAC_CTRL_PRMLEN_MASK 0xf +#define MAC_CTRL_RMV_VLAN 0x4000 +#define MAC_CTRL_PROMIS_EN 0x8000 +#define MAC_CTRL_TX_PAUSE 0x10000 +#define MAC_CTRL_SCNT 0x20000 +#define MAC_CTRL_SRST_TX 0x40000 +#define MAC_CTRL_TX_SIMURST 0x80000 +#define MAC_CTRL_SPEED_SHIFT 20 +#define MAC_CTRL_SPEED_MASK 0x300000 +#define MAC_CTRL_SPEED_1000 2 +#define MAC_CTRL_SPEED_10_100 1 +#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000 +#define MAC_CTRL_TX_HUGE 0x800000 +#define MAC_CTRL_RX_CHKSUM_EN 0x1000000 +#define MAC_CTRL_MC_ALL_EN 0x2000000 +#define MAC_CTRL_BC_EN 0x4000000 +#define MAC_CTRL_DBG 0x8000000 + +/* MAC IPG/IFG Control Register */ +#define REG_MAC_IPG_IFG 0x1484 +#define MAC_IPG_IFG_IPGT_SHIFT 0 +#define MAC_IPG_IFG_IPGT_MASK 0x7f +#define MAC_IPG_IFG_MIFG_SHIFT 8 +#define MAC_IPG_IFG_MIFG_MASK 0xff +#define MAC_IPG_IFG_IPGR1_SHIFT 16 +#define MAC_IPG_IFG_IPGR1_MASK 0x7f +#define MAC_IPG_IFG_IPGR2_SHIFT 24 +#define MAC_IPG_IFG_IPGR2_MASK 0x7f + +/* MAC STATION ADDRESS */ +#define REG_MAC_STA_ADDR 0x1488 + +/* Hash table for multicast address */ +#define REG_RX_HASH_TABLE 0x1490 + +/* MAC Half-Duplex Control Register */ +#define REG_MAC_HALF_DUPLX_CTRL 0x1498 +#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT 0 +#define MAC_HALF_DUPLX_CTRL_LCOL_MASK 0x3ff +#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12 +#define MAC_HALF_DUPLX_CTRL_RETRY_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN 0x10000 +#define MAC_HALF_DUPLX_CTRL_NO_BACK_C 0x20000 +#define MAC_HALF_DUPLX_CTRL_NO_BACK_P 0x40000 +#define MAC_HALF_DUPLX_CTRL_ABEBE 0x80000 +#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT 20 +#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24 +#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK 0xf + +/* Maximum Frame Length Control Register */ +#define REG_MTU 0x149c + +/* Wake-On-Lan control register */ +#define REG_WOL_CTRL 0x14a0 +#define WOL_PATTERN_EN 0x00000001 +#define WOL_PATTERN_PME_EN 0x00000002 +#define WOL_MAGIC_EN 0x00000004 +#define WOL_MAGIC_PME_EN 0x00000008 +#define WOL_LINK_CHG_EN 0x00000010 +#define WOL_LINK_CHG_PME_EN 0x00000020 +#define WOL_PATTERN_ST 0x00000100 +#define WOL_MAGIC_ST 0x00000200 +#define WOL_LINKCHG_ST 0x00000400 +#define WOL_CLK_SWITCH_EN 0x00008000 +#define WOL_PT0_EN 0x00010000 +#define WOL_PT1_EN 0x00020000 +#define WOL_PT2_EN 0x00040000 +#define WOL_PT3_EN 0x00080000 +#define WOL_PT4_EN 0x00100000 +#define WOL_PT5_EN 0x00200000 +#define WOL_PT6_EN 0x00400000 + +/* WOL Length ( 2 DWORD ) */ +#define REG_WOL_PATTERN_LEN 0x14a4 +#define WOL_PT_LEN_MASK 0x7f +#define WOL_PT0_LEN_SHIFT 0 +#define WOL_PT1_LEN_SHIFT 8 +#define WOL_PT2_LEN_SHIFT 16 +#define WOL_PT3_LEN_SHIFT 24 +#define WOL_PT4_LEN_SHIFT 0 +#define WOL_PT5_LEN_SHIFT 8 +#define WOL_PT6_LEN_SHIFT 16 + +/* Internal SRAM Partition Register */ +#define REG_SRAM_RFD_ADDR 0x1500 +#define REG_SRAM_RFD_LEN (REG_SRAM_RFD_ADDR+ 4) +#define REG_SRAM_RRD_ADDR (REG_SRAM_RFD_ADDR+ 8) +#define REG_SRAM_RRD_LEN (REG_SRAM_RFD_ADDR+12) +#define REG_SRAM_TPD_ADDR (REG_SRAM_RFD_ADDR+16) +#define REG_SRAM_TPD_LEN (REG_SRAM_RFD_ADDR+20) +#define REG_SRAM_TRD_ADDR (REG_SRAM_RFD_ADDR+24) +#define REG_SRAM_TRD_LEN (REG_SRAM_RFD_ADDR+28) +#define REG_SRAM_RXF_ADDR (REG_SRAM_RFD_ADDR+32) +#define REG_SRAM_RXF_LEN (REG_SRAM_RFD_ADDR+36) +#define REG_SRAM_TXF_ADDR (REG_SRAM_RFD_ADDR+40) +#define REG_SRAM_TXF_LEN (REG_SRAM_RFD_ADDR+44) +#define REG_SRAM_TCPH_PATH_ADDR (REG_SRAM_RFD_ADDR+48) +#define SRAM_TCPH_ADDR_MASK 0x0fff +#define SRAM_TCPH_ADDR_SHIFT 0 +#define SRAM_PATH_ADDR_MASK 0x0fff +#define SRAM_PATH_ADDR_SHIFT 16 + +/* Load Ptr Register */ +#define REG_LOAD_PTR (REG_SRAM_RFD_ADDR+52) + +/* Descriptor Control register */ +#define REG_DESC_BASE_ADDR_HI 0x1540 +#define REG_DESC_RFD_ADDR_LO (REG_DESC_BASE_ADDR_HI+4) +#define REG_DESC_RRD_ADDR_LO (REG_DESC_BASE_ADDR_HI+8) +#define REG_DESC_TPD_ADDR_LO (REG_DESC_BASE_ADDR_HI+12) +#define REG_DESC_CMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+16) +#define REG_DESC_SMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+20) +#define REG_DESC_RFD_RRD_RING_SIZE (REG_DESC_BASE_ADDR_HI+24) +#define DESC_RFD_RING_SIZE_MASK 0x7ff +#define DESC_RFD_RING_SIZE_SHIFT 0 +#define DESC_RRD_RING_SIZE_MASK 0x7ff +#define DESC_RRD_RING_SIZE_SHIFT 16 +#define REG_DESC_TPD_RING_SIZE (REG_DESC_BASE_ADDR_HI+28) +#define DESC_TPD_RING_SIZE_MASK 0x3ff +#define DESC_TPD_RING_SIZE_SHIFT 0 + +/* TXQ Control Register */ +#define REG_TXQ_CTRL 0x1580 +#define TXQ_CTRL_TPD_BURST_NUM_SHIFT 0 +#define TXQ_CTRL_TPD_BURST_NUM_MASK 0x1f +#define TXQ_CTRL_EN 0x20 +#define TXQ_CTRL_ENH_MODE 0x40 +#define TXQ_CTRL_TPD_FETCH_TH_SHIFT 8 +#define TXQ_CTRL_TPD_FETCH_TH_MASK 0x3f +#define TXQ_CTRL_TXF_BURST_NUM_SHIFT 16 +#define TXQ_CTRL_TXF_BURST_NUM_MASK 0xffff + +/* Jumbo packet Threshold for task offload */ +#define REG_TX_JUMBO_TASK_TH_TPD_IPG 0x1584 +#define TX_JUMBO_TASK_TH_MASK 0x7ff +#define TX_JUMBO_TASK_TH_SHIFT 0 +#define TX_TPD_MIN_IPG_MASK 0x1f +#define TX_TPD_MIN_IPG_SHIFT 16 + +/* RXQ Control Register */ +#define REG_RXQ_CTRL 0x15a0 +#define RXQ_CTRL_RFD_BURST_NUM_SHIFT 0 +#define RXQ_CTRL_RFD_BURST_NUM_MASK 0xff +#define RXQ_CTRL_RRD_BURST_THRESH_SHIFT 8 +#define RXQ_CTRL_RRD_BURST_THRESH_MASK 0xff +#define RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT 16 +#define RXQ_CTRL_RFD_PREF_MIN_IPG_MASK 0x1f +#define RXQ_CTRL_CUT_THRU_EN 0x40000000 +#define RXQ_CTRL_EN 0x80000000 + +/* Rx jumbo packet threshold and rrd retirement timer */ +#define REG_RXQ_JMBOSZ_RRDTIM (REG_RXQ_CTRL+ 4) +#define RXQ_JMBOSZ_TH_MASK 0x7ff +#define RXQ_JMBOSZ_TH_SHIFT 0 +#define RXQ_JMBO_LKAH_MASK 0xf +#define RXQ_JMBO_LKAH_SHIFT 11 +#define RXQ_RRD_TIMER_MASK 0xffff +#define RXQ_RRD_TIMER_SHIFT 16 + +/* RFD flow control register */ +#define REG_RXQ_RXF_PAUSE_THRESH (REG_RXQ_CTRL+ 8) +#define RXQ_RXF_PAUSE_TH_HI_SHIFT 16 +#define RXQ_RXF_PAUSE_TH_HI_MASK 0xfff +#define RXQ_RXF_PAUSE_TH_LO_SHIFT 0 +#define RXQ_RXF_PAUSE_TH_LO_MASK 0xfff + +/* RRD flow control register */ +#define REG_RXQ_RRD_PAUSE_THRESH (REG_RXQ_CTRL+12) +#define RXQ_RRD_PAUSE_TH_HI_SHIFT 0 +#define RXQ_RRD_PAUSE_TH_HI_MASK 0xfff +#define RXQ_RRD_PAUSE_TH_LO_SHIFT 16 +#define RXQ_RRD_PAUSE_TH_LO_MASK 0xfff + +/* DMA Engine Control Register */ +#define REG_DMA_CTRL 0x15c0 +#define DMA_CTRL_DMAR_IN_ORDER 0x1 +#define DMA_CTRL_DMAR_ENH_ORDER 0x2 +#define DMA_CTRL_DMAR_OUT_ORDER 0x4 +#define DMA_CTRL_RCB_VALUE 0x8 +#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4 +#define DMA_CTRL_DMAR_BURST_LEN_MASK 7 +#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7 +#define DMA_CTRL_DMAW_BURST_LEN_MASK 7 +#define DMA_CTRL_DMAR_EN 0x400 +#define DMA_CTRL_DMAW_EN 0x800 + +/* CMB/SMB Control Register */ +#define REG_CSMB_CTRL 0x15d0 +#define CSMB_CTRL_CMB_NOW 1 +#define CSMB_CTRL_SMB_NOW 2 +#define CSMB_CTRL_CMB_EN 4 +#define CSMB_CTRL_SMB_EN 8 + +/* CMB DMA Write Threshold Register */ +#define REG_CMB_WRITE_TH (REG_CSMB_CTRL+ 4) +#define CMB_RRD_TH_SHIFT 0 +#define CMB_RRD_TH_MASK 0x7ff +#define CMB_TPD_TH_SHIFT 16 +#define CMB_TPD_TH_MASK 0x7ff + +/* RX/TX count-down timer to trigger CMB-write. 2us resolution. */ +#define REG_CMB_WRITE_TIMER (REG_CSMB_CTRL+ 8) +#define CMB_RX_TM_SHIFT 0 +#define CMB_RX_TM_MASK 0xffff +#define CMB_TX_TM_SHIFT 16 +#define CMB_TX_TM_MASK 0xffff + +/* Number of packet received since last CMB write */ +#define REG_CMB_RX_PKT_CNT (REG_CSMB_CTRL+12) + +/* Number of packet transmitted since last CMB write */ +#define REG_CMB_TX_PKT_CNT (REG_CSMB_CTRL+16) + +/* SMB auto DMA timer register */ +#define REG_SMB_TIMER (REG_CSMB_CTRL+20) + +/* Mailbox Register */ +#define REG_MAILBOX 0x15f0 +#define MB_RFD_PROD_INDX_SHIFT 0 +#define MB_RFD_PROD_INDX_MASK 0x7ff +#define MB_RRD_CONS_INDX_SHIFT 11 +#define MB_RRD_CONS_INDX_MASK 0x7ff +#define MB_TPD_PROD_INDX_SHIFT 22 +#define MB_TPD_PROD_INDX_MASK 0x3ff + +/* Interrupt Status Register */ +#define REG_ISR 0x1600 +#define ISR_SMB 1 +#define ISR_TIMER 2 +#define ISR_MANUAL 4 +#define ISR_RXF_OV 8 +#define ISR_RFD_UNRUN 0x10 +#define ISR_RRD_OV 0x20 +#define ISR_TXF_UNRUN 0x40 +#define ISR_LINK 0x80 +#define ISR_HOST_RFD_UNRUN 0x100 +#define ISR_HOST_RRD_OV 0x200 +#define ISR_DMAR_TO_RST 0x400 +#define ISR_DMAW_TO_RST 0x800 +#define ISR_GPHY 0x1000 +#define ISR_RX_PKT 0x10000 +#define ISR_TX_PKT 0x20000 +#define ISR_TX_DMA 0x40000 +#define ISR_RX_DMA 0x80000 +#define ISR_CMB_RX 0x100000 +#define ISR_CMB_TX 0x200000 +#define ISR_MAC_RX 0x400000 +#define ISR_MAC_TX 0x800000 +#define ISR_UR_DETECTED 0x1000000 +#define ISR_FERR_DETECTED 0x2000000 +#define ISR_NFERR_DETECTED 0x4000000 +#define ISR_CERR_DETECTED 0x8000000 +#define ISR_PHY_LINKDOWN 0x10000000 +#define ISR_DIS_SMB 0x20000000 +#define ISR_DIS_DMA 0x40000000 +#define ISR_DIS_INT 0x80000000 + +/* Interrupt Mask Register */ +#define REG_IMR 0x1604 + +/* Normal Interrupt mask */ +#define IMR_NORMAL_MASK (\ + ISR_SMB |\ + ISR_GPHY |\ + ISR_PHY_LINKDOWN|\ + ISR_DMAR_TO_RST |\ + ISR_DMAW_TO_RST |\ + ISR_CMB_TX |\ + ISR_CMB_RX ) + +/* Debug Interrupt Mask (enable all interrupt) */ +#define IMR_DEBUG_MASK (\ + ISR_SMB |\ + ISR_TIMER |\ + ISR_MANUAL |\ + ISR_RXF_OV |\ + ISR_RFD_UNRUN |\ + ISR_RRD_OV |\ + ISR_TXF_UNRUN |\ + ISR_LINK |\ + ISR_CMB_TX |\ + ISR_CMB_RX |\ + ISR_RX_PKT |\ + ISR_TX_PKT |\ + ISR_MAC_RX |\ + ISR_MAC_TX ) + +/* Interrupt Status Register */ +#define REG_RFD_RRD_IDX 0x1800 +#define REG_TPD_IDX 0x1804 + +/* MII definition */ +/* PHY Common Register */ +#define MII_AT001_CR 0x09 +#define MII_AT001_SR 0x0A +#define MII_AT001_ESR 0x0F +#define MII_AT001_PSCR 0x10 +#define MII_AT001_PSSR 0x11 + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_MASK 0x2040 +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Link partner ability register. */ +#define MII_LPA_SLCT 0x001f /* Same as advertise selector */ +#define MII_LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ +#define MII_LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ +#define MII_LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ +#define MII_LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ +#define MII_LPA_100BASE4 0x0200 /* 100BASE-T4 */ +#define MII_LPA_PAUSE 0x0400 /* PAUSE */ +#define MII_LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */ +#define MII_LPA_RFAULT 0x2000 /* Link partner faulted */ +#define MII_LPA_LPACK 0x4000 /* Link partner acked us */ +#define MII_LPA_NPAGE 0x8000 /* Next page bit */ + +/* Autoneg Advertisement Register */ +#define MII_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define MII_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define MII_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define MII_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define MII_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define MII_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define MII_AR_PAUSE 0x0400 /* Pause operation desired */ +#define MII_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define MII_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define MII_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ +#define MII_AR_SPEED_MASK 0x01E0 +#define MII_AR_DEFAULT_CAP_MASK 0x0DE0 + +/* 1000BASE-T Control Register */ +#define MII_AT001_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define MII_AT001_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define MII_AT001_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port, 0=DTE device */ +#define MII_AT001_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master, 0=Configure PHY as Slave */ +#define MII_AT001_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value, 0=Automatic Master/Slave config */ +#define MII_AT001_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define MII_AT001_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define MII_AT001_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ +#define MII_AT001_CR_1000T_SPEED_MASK 0x0300 +#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK 0x0300 + +/* 1000BASE-T Status Register */ +#define MII_AT001_SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define MII_AT001_SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define MII_AT001_SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define MII_AT001_SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +/* Extended Status Register */ +#define MII_AT001_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define MII_AT001_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define MII_AT001_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define MII_AT001_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +/* AT001 PHY Specific Control Register */ +#define MII_AT001_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define MII_AT001_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define MII_AT001_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ +#define MII_AT001_PSCR_MAC_POWERDOWN 0x0008 +#define MII_AT001_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, 0=CLK125 toggling */ +#define MII_AT001_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5, Manual MDI configuration */ +#define MII_AT001_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define MII_AT001_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ +#define MII_AT001_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled all speeds. */ +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold), 0=Normal 10BASE-T RX Threshold */ +#define MII_AT001_PSCR_MII_5BIT_ENABLE 0x0100 /* 1=5-Bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ +#define MII_AT001_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define MII_AT001_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define MII_AT001_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ +#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT 5 +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +/* AT001 PHY Specific Status Register */ +#define MII_AT001_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define MII_AT001_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define MII_AT001_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define MII_AT001_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define MII_AT001_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define MII_AT001_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +/* PCI Command Register Bit Definitions */ +#define PCI_REG_COMMAND 0x04 /* PCI Command Register */ +#define CMD_IO_SPACE 0x0001 +#define CMD_MEMORY_SPACE 0x0002 +#define CMD_BUS_MASTER 0x0004 + +/* Wake Up Filter Control */ +#define ATL1_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define ATL1_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define ATL1_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define ATL1_WUFC_MC 0x00000008 /* Multicast Wakeup Enable */ +#define ATL1_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ + +/* Error Codes */ +#define ATL1_SUCCESS 0 +#define ATL1_ERR_EEPROM 1 +#define ATL1_ERR_PHY 2 +#define ATL1_ERR_CONFIG 3 +#define ATL1_ERR_PARAM 4 +#define ATL1_ERR_MAC_TYPE 5 +#define ATL1_ERR_PHY_TYPE 6 +#define ATL1_ERR_PHY_SPEED 7 +#define ATL1_ERR_PHY_RES 8 + +#define SPEED_0 0xffff +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +#define MEDIA_TYPE_AUTO_SENSOR 0 +#define MEDIA_TYPE_1000M_FULL 1 +#define MEDIA_TYPE_100M_FULL 2 +#define MEDIA_TYPE_100M_HALF 3 +#define MEDIA_TYPE_10M_FULL 4 +#define MEDIA_TYPE_10M_HALF 5 + +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 +#define ADVERTISE_1000_FULL 0x0020 +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ +#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds */ +#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds */ + +/* The size (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */ +#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */ +#define ETHERNET_FCS_SIZE 4 +#define MAX_JUMBO_FRAME_SIZE 0x2800 + +#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ + +/* For checksumming , the sum of all words in the EEPROM should equal 0xBABA */ +#define EEPROM_SUM 0xBABA + +#define ATL1_EEDUMP_LEN 48 + +/* Statistics counters collected by the MAC */ +struct stats_msg_block { + /* rx */ + u32 rx_ok; /* The number of good packet received. */ + u32 rx_bcast; /* The number of good broadcast packet received. */ + u32 rx_mcast; /* The number of good multicast packet received. */ + u32 rx_pause; /* The number of Pause packet received. */ + u32 rx_ctrl; /* The number of Control packet received other than Pause frame. */ + u32 rx_fcs_err; /* The number of packets with bad FCS. */ + u32 rx_len_err; /* The number of packets with mismatch of length field and actual size. */ + u32 rx_byte_cnt; /* The number of bytes of good packet received. FCS is NOT included. */ + u32 rx_runt; /* The number of packets received that are less than 64 byte long and with good FCS. */ + u32 rx_frag; /* The number of packets received that are less than 64 byte long and with bad FCS. */ + u32 rx_sz_64; /* The number of good and bad packets received that are 64 byte long. */ + u32 rx_sz_65_127; /* The number of good and bad packets received that are between 65 and 127-byte long. */ + u32 rx_sz_128_255; /* The number of good and bad packets received that are between 128 and 255-byte long. */ + u32 rx_sz_256_511; /* The number of good and bad packets received that are between 256 and 511-byte long. */ + u32 rx_sz_512_1023; /* The number of good and bad packets received that are between 512 and 1023-byte long. */ + u32 rx_sz_1024_1518; /* The number of good and bad packets received that are between 1024 and 1518-byte long. */ + u32 rx_sz_1519_max; /* The number of good and bad packets received that are between 1519-byte and MTU. */ + u32 rx_sz_ov; /* The number of good and bad packets received that are more than MTU size Å¡C truncated by Selene. */ + u32 rx_rxf_ov; /* The number of frame dropped due to occurrence of RX FIFO overflow. */ + u32 rx_rrd_ov; /* The number of frame dropped due to occurrence of RRD overflow. */ + u32 rx_align_err; /* Alignment Error */ + u32 rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */ + u32 rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */ + u32 rx_err_addr; /* The number of packets dropped due to address filtering. */ + + /* tx */ + u32 tx_ok; /* The number of good packet transmitted. */ + u32 tx_bcast; /* The number of good broadcast packet transmitted. */ + u32 tx_mcast; /* The number of good multicast packet transmitted. */ + u32 tx_pause; /* The number of Pause packet transmitted. */ + u32 tx_exc_defer; /* The number of packets transmitted with excessive deferral. */ + u32 tx_ctrl; /* The number of packets transmitted is a control frame, excluding Pause frame. */ + u32 tx_defer; /* The number of packets transmitted that is deferred. */ + u32 tx_byte_cnt; /* The number of bytes of data transmitted. FCS is NOT included. */ + u32 tx_sz_64; /* The number of good and bad packets transmitted that are 64 byte long. */ + u32 tx_sz_65_127; /* The number of good and bad packets transmitted that are between 65 and 127-byte long. */ + u32 tx_sz_128_255; /* The number of good and bad packets transmitted that are between 128 and 255-byte long. */ + u32 tx_sz_256_511; /* The number of good and bad packets transmitted that are between 256 and 511-byte long. */ + u32 tx_sz_512_1023; /* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */ + u32 tx_sz_1024_1518; /* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */ + u32 tx_sz_1519_max; /* The number of good and bad packets transmitted that are between 1519-byte and MTU. */ + u32 tx_1_col; /* The number of packets subsequently transmitted successfully with a single prior collision. */ + u32 tx_2_col; /* The number of packets subsequently transmitted successfully with multiple prior collisions. */ + u32 tx_late_col; /* The number of packets transmitted with late collisions. */ + u32 tx_abort_col; /* The number of transmit packets aborted due to excessive collisions. */ + u32 tx_underrun; /* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ + u32 tx_rd_eop; /* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */ + u32 tx_len_err; /* The number of transmit packets with length field does NOT match the actual frame size. */ + u32 tx_trunc; /* The number of transmit packets truncated due to size exceeding MTU. */ + u32 tx_bcast_byte; /* The byte count of broadcast packet transmitted, excluding FCS. */ + u32 tx_mcast_byte; /* The byte count of multicast packet transmitted, excluding FCS. */ + u32 smb_updated; /* 1: SMB Updated. This is used by software as the indication of the statistics update. + * Software should clear this bit as soon as retrieving the statistics information. */ +}; + +/* Coalescing Message Block */ +struct coals_msg_block { + u32 int_stats; /* interrupt status */ + u16 rrd_prod_idx; /* TRD Producer Index. */ + u16 rfd_cons_idx; /* RFD Consumer Index. */ + u16 update; /* Selene sets this bit every time it DMA the CMB to host memory. + * Software supposes to clear this bit when CMB information is processed. */ + u16 tpd_cons_idx; /* TPD Consumer Index. */ +}; + +/* RRD descriptor */ +struct rx_return_desc { + u8 num_buf; /* Number of RFD buffers used by the received packet */ + u8 resved; + u16 buf_indx; /* RFD Index of the first buffer */ + union { + u32 valid; + struct { + u16 rx_chksum; + u16 pkt_size; + } xsum_sz; + } xsz; + + u16 pkt_flg; /* Packet flags */ + u16 err_flg; /* Error flags */ + u16 resved2; + u16 vlan_tag; /* VLAN TAG */ +}; + +#define PACKET_FLAG_ETH_TYPE 0x0080 +#define PACKET_FLAG_VLAN_INS 0x0100 +#define PACKET_FLAG_ERR 0x0200 +#define PACKET_FLAG_IPV4 0x0400 +#define PACKET_FLAG_UDP 0x0800 +#define PACKET_FLAG_TCP 0x1000 +#define PACKET_FLAG_BCAST 0x2000 +#define PACKET_FLAG_MCAST 0x4000 +#define PACKET_FLAG_PAUSE 0x8000 + +#define ERR_FLAG_CRC 0x0001 +#define ERR_FLAG_CODE 0x0002 +#define ERR_FLAG_DRIBBLE 0x0004 +#define ERR_FLAG_RUNT 0x0008 +#define ERR_FLAG_OV 0x0010 +#define ERR_FLAG_TRUNC 0x0020 +#define ERR_FLAG_IP_CHKSUM 0x0040 +#define ERR_FLAG_L4_CHKSUM 0x0080 +#define ERR_FLAG_LEN 0x0100 +#define ERR_FLAG_DES_ADDR 0x0200 + +/* RFD descriptor */ +struct rx_free_desc { + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 buf_len; /* Size of the receive buffer in host memory, in byte */ + u16 coalese; /* Update consumer index to host after the reception of this frame */ + /* __attribute__ ((packed)) is required */ +} __attribute__ ((packed)); + +/* tsopu defines */ +#define TSO_PARAM_BUFLEN_MASK 0x3FFF +#define TSO_PARAM_BUFLEN_SHIFT 0 +#define TSO_PARAM_DMAINT_MASK 0x0001 +#define TSO_PARAM_DMAINT_SHIFT 14 +#define TSO_PARAM_PKTNT_MASK 0x0001 +#define TSO_PARAM_PKTINT_SHIFT 15 +#define TSO_PARAM_VLANTAG_MASK 0xFFFF +#define TSO_PARAM_VLAN_SHIFT 16 + +/* tsopl defines */ +#define TSO_PARAM_EOP_MASK 0x0001 +#define TSO_PARAM_EOP_SHIFT 0 +#define TSO_PARAM_COALESCE_MASK 0x0001 +#define TSO_PARAM_COALESCE_SHIFT 1 +#define TSO_PARAM_INSVLAG_MASK 0x0001 +#define TSO_PARAM_INSVLAG_SHIFT 2 +#define TSO_PARAM_CUSTOMCKSUM_MASK 0x0001 +#define TSO_PARAM_CUSTOMCKSUM_SHIFT 3 +#define TSO_PARAM_SEGMENT_MASK 0x0001 +#define TSO_PARAM_SEGMENT_SHIFT 4 +#define TSO_PARAM_IPCKSUM_MASK 0x0001 +#define TSO_PARAM_IPCKSUM_SHIFT 5 +#define TSO_PARAM_TCPCKSUM_MASK 0x0001 +#define TSO_PARAM_TCPCKSUM_SHIFT 6 +#define TSO_PARAM_UDPCKSUM_MASK 0x0001 +#define TSO_PARAM_UDPCKSUM_SHIFT 7 +#define TSO_PARAM_VLANTAGGED_MASK 0x0001 +#define TSO_PARAM_VLANTAGGED_SHIFT 8 +#define TSO_PARAM_ETHTYPE_MASK 0x0001 +#define TSO_PARAM_ETHTYPE_SHIFT 9 +#define TSO_PARAM_IPHL_MASK 0x000F +#define TSO_PARAM_IPHL_SHIFT 10 +#define TSO_PARAM_TCPHDRLEN_MASK 0x000F +#define TSO_PARAM_TCPHDRLEN_SHIFT 14 +#define TSO_PARAM_HDRFLAG_MASK 0x0001 +#define TSO_PARAM_HDRFLAG_SHIFT 18 +#define TSO_PARAM_MSS_MASK 0x1FFF +#define TSO_PARAM_MSS_SHIFT 19 + +/* csumpu defines */ +#define CSUM_PARAM_BUFLEN_MASK 0x3FFF +#define CSUM_PARAM_BUFLEN_SHIFT 0 +#define CSUM_PARAM_DMAINT_MASK 0x0001 +#define CSUM_PARAM_DMAINT_SHIFT 14 +#define CSUM_PARAM_PKTINT_MASK 0x0001 +#define CSUM_PARAM_PKTINT_SHIFT 15 +#define CSUM_PARAM_VALANTAG_MASK 0xFFFF +#define CSUM_PARAM_VALAN_SHIFT 16 + +/* csumpl defines*/ +#define CSUM_PARAM_EOP_MASK 0x0001 +#define CSUM_PARAM_EOP_SHIFT 0 +#define CSUM_PARAM_COALESCE_MASK 0x0001 +#define CSUM_PARAM_COALESCE_SHIFT 1 +#define CSUM_PARAM_INSVLAG_MASK 0x0001 +#define CSUM_PARAM_INSVLAG_SHIFT 2 +#define CSUM_PARAM_CUSTOMCKSUM_MASK 0x0001 +#define CSUM_PARAM_CUSTOMCKSUM_SHIFT 3 +#define CSUM_PARAM_SEGMENT_MASK 0x0001 +#define CSUM_PARAM_SEGMENT_SHIFT 4 +#define CSUM_PARAM_IPCKSUM_MASK 0x0001 +#define CSUM_PARAM_IPCKSUM_SHIFT 5 +#define CSUM_PARAM_TCPCKSUM_MASK 0x0001 +#define CSUM_PARAM_TCPCKSUM_SHIFT 6 +#define CSUM_PARAM_UDPCKSUM_MASK 0x0001 +#define CSUM_PARAM_UDPCKSUM_SHIFT 7 +#define CSUM_PARAM_VLANTAGGED_MASK 0x0001 +#define CSUM_PARAM_VLANTAGGED_SHIFT 8 +#define CSUM_PARAM_ETHTYPE_MASK 0x0001 +#define CSUM_PARAM_ETHTYPE_SHIFT 9 +#define CSUM_PARAM_IPHL_MASK 0x000F +#define CSUM_PARAM_IPHL_SHIFT 10 +#define CSUM_PARAM_PLOADOFFSET_MASK 0x00FF +#define CSUM_PARAM_PLOADOFFSET_SHIFT 16 +#define CSUM_PARAM_XSUMOFFSET_MASK 0x00FF +#define CSUM_PARAM_XSUMOFFSET_SHIFT 24 + +/* TPD descriptor */ +struct tso_param { + /* The order of these declarations is important -- don't change it */ + u32 tsopu; /* tso_param upper word */ + u32 tsopl; /* tso_param lower word */ +}; + +struct csum_param { + /* The order of these declarations is important -- don't change it */ + u32 csumpu; /* csum_param upper word */ + u32 csumpl; /* csum_param lower word */ +}; + +union tpd_descr { + u64 data; + struct csum_param csum; + struct tso_param tso; +}; + +struct tx_packet_desc { + __le64 buffer_addr; + union tpd_descr desc; +}; + +/* DMA Order Settings */ +enum atl1_dma_order { + atl1_dma_ord_in = 1, + atl1_dma_ord_enh = 2, + atl1_dma_ord_out = 4 +}; + +enum atl1_dma_rcb { + atl1_rcb_64 = 0, + atl1_rcb_128 = 1 +}; + +enum atl1_dma_req_block { + atl1_dma_req_128 = 0, + atl1_dma_req_256 = 1, + atl1_dma_req_512 = 2, + atl1_dam_req_1024 = 3, + atl1_dam_req_2048 = 4, + atl1_dma_req_4096 = 5 +}; + +struct atl1_spi_flash_dev { + const char *manu_name; /* manufacturer id */ + /* op-code */ + u8 cmd_wrsr; + u8 cmd_read; + u8 cmd_program; + u8 cmd_wren; + u8 cmd_wrdi; + u8 cmd_rdsr; + u8 cmd_rdid; + u8 cmd_sector_erase; + u8 cmd_chip_erase; +}; + +#endif /* _ATL1_HW_H_ */ diff --git a/trunk/drivers/net/atl1/atl1_main.c b/trunk/drivers/net/atl1/atl1_main.c new file mode 100644 index 000000000000..6655640eb4ca --- /dev/null +++ b/trunk/drivers/net/atl1/atl1_main.c @@ -0,0 +1,2468 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * 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 full GNU General Public License is included in this distribution in the + * file called COPYING. + * + * Contact Information: + * Xiong Huang + * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei, + * Xinzhu 302, TAIWAN, REPUBLIC OF CHINA + * + * Chris Snook + * Jay Cliburn + * + * This version is adapted from the Attansic reference driver for + * inclusion in the Linux kernel. It is currently under heavy development. + * A very incomplete list of things that need to be dealt with: + * + * TODO: + * Fix TSO; tx performance is horrible with TSO enabled. + * Wake on LAN. + * Add more ethtool functions, including set ring parameters. + * Fix abstruse irq enable/disable condition described here: + * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2 + * + * NEEDS TESTING: + * VLAN + * multicast + * promiscuous mode + * interrupt coalescing + * SMP torture testing + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "atl1.h" + +#define RUN_REALTIME 0 +#define DRIVER_VERSION "2.0.6" + +char atl1_driver_name[] = "atl1"; +static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver"; +static const char atl1_copyright[] = "Copyright(c) 2005-2006 Attansic Corporation."; +char atl1_driver_version[] = DRIVER_VERSION; + +MODULE_AUTHOR + ("Attansic Corporation , Chris Snook , Jay Cliburn "); +MODULE_DESCRIPTION("Attansic 1000M Ethernet Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); + +/* + * atl1_pci_tbl - PCI Device ID Table + */ +static const struct pci_device_id atl1_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1048)}, + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, atl1_pci_tbl); + +/* + * atl1_sw_init - Initialize general software structures (struct atl1_adapter) + * @adapter: board private structure to initialize + * + * atl1_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + */ +static int __devinit atl1_sw_init(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + + /* PCI config space info */ + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + + hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE; + + adapter->wol = 0; + adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7; + adapter->ict = 50000; /* 100ms */ + adapter->link_speed = SPEED_0; /* hardware init */ + adapter->link_duplex = FULL_DUPLEX; + + hw->phy_configured = false; + hw->preamble_len = 7; + hw->ipgt = 0x60; + hw->min_ifg = 0x50; + hw->ipgr1 = 0x40; + hw->ipgr2 = 0x60; + hw->max_retry = 0xf; + hw->lcol = 0x37; + hw->jam_ipg = 7; + hw->rfd_burst = 8; + hw->rrd_burst = 8; + hw->rfd_fetch_gap = 1; + hw->rx_jumbo_th = adapter->rx_buffer_len / 8; + hw->rx_jumbo_lkah = 1; + hw->rrd_ret_timer = 16; + hw->tpd_burst = 4; + hw->tpd_fetch_th = 16; + hw->txf_burst = 0x100; + hw->tx_jumbo_task_th = (hw->max_frame_size + 7) >> 3; + hw->tpd_fetch_gap = 1; + hw->rcb_value = atl1_rcb_64; + hw->dma_ord = atl1_dma_ord_enh; + hw->dmar_block = atl1_dma_req_256; + hw->dmaw_block = atl1_dma_req_256; + hw->cmb_rrd = 4; + hw->cmb_tpd = 4; + hw->cmb_rx_timer = 1; /* about 2us */ + hw->cmb_tx_timer = 1; /* about 2us */ + hw->smb_timer = 100000; /* about 200ms */ + + atomic_set(&adapter->irq_sem, 0); + spin_lock_init(&adapter->lock); + spin_lock_init(&adapter->mb_lock); + + return 0; +} + +/* + * atl1_setup_mem_resources - allocate Tx / RX descriptor resources + * @adapter: board private structure + * + * Return 0 on success, negative on failure + */ +s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_ring_header *ring_header = &adapter->ring_header; + struct pci_dev *pdev = adapter->pdev; + int size; + u8 offset = 0; + + size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count); + tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL); + if (unlikely(!tpd_ring->buffer_info)) { + printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n", + atl1_driver_name, size); + goto err_nomem; + } + rfd_ring->buffer_info = + (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count); + + /* real ring DMA buffer */ + ring_header->size = size = sizeof(struct tx_packet_desc) * + tpd_ring->count + + sizeof(struct rx_free_desc) * rfd_ring->count + + sizeof(struct rx_return_desc) * rrd_ring->count + + sizeof(struct coals_msg_block) + + sizeof(struct stats_msg_block) + + 40; /* "40: for 8 bytes align" huh? -- CHS */ + + ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, + &ring_header->dma); + if (unlikely(!ring_header->desc)) { + printk(KERN_WARNING + "%s: pci_alloc_consistent failed, size = D%d\n", + atl1_driver_name, size); + goto err_nomem; + } + + memset(ring_header->desc, 0, ring_header->size); + + /* init TPD ring */ + tpd_ring->dma = ring_header->dma; + offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0; + tpd_ring->dma += offset; + tpd_ring->desc = (u8 *) ring_header->desc + offset; + tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count; + atomic_set(&tpd_ring->next_to_use, 0); + atomic_set(&tpd_ring->next_to_clean, 0); + + /* init RFD ring */ + rfd_ring->dma = tpd_ring->dma + tpd_ring->size; + offset = (rfd_ring->dma & 0x7) ? (8 - (rfd_ring->dma & 0x7)) : 0; + rfd_ring->dma += offset; + rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset); + rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count; + rfd_ring->next_to_clean = 0; + /* rfd_ring->next_to_use = rfd_ring->count - 1; */ + atomic_set(&rfd_ring->next_to_use, 0); + + /* init RRD ring */ + rrd_ring->dma = rfd_ring->dma + rfd_ring->size; + offset = (rrd_ring->dma & 0x7) ? (8 - (rrd_ring->dma & 0x7)) : 0; + rrd_ring->dma += offset; + rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset); + rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count; + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); + + /* init CMB */ + adapter->cmb.dma = rrd_ring->dma + rrd_ring->size; + offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0; + adapter->cmb.dma += offset; + adapter->cmb.cmb = + (struct coals_msg_block *) ((u8 *) rrd_ring->desc + + (rrd_ring->size + offset)); + + /* init SMB */ + adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block); + offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0; + adapter->smb.dma += offset; + adapter->smb.smb = (struct stats_msg_block *) + ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset)); + + return ATL1_SUCCESS; + +err_nomem: + kfree(tpd_ring->buffer_info); + return -ENOMEM; +} + +/* + * atl1_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + */ +static void atl1_irq_enable(struct atl1_adapter *adapter) +{ + if (likely(!atomic_dec_and_test(&adapter->irq_sem))) + iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR); +} + +static void atl1_clear_phy_int(struct atl1_adapter *adapter) +{ + u16 phy_data; + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + atl1_read_phy_reg(&adapter->hw, 19, &phy_data); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +static void atl1_inc_smb(struct atl1_adapter *adapter) +{ + struct stats_msg_block *smb = adapter->smb.smb; + + /* Fill out the OS statistics structure */ + adapter->soft_stats.rx_packets += smb->rx_ok; + adapter->soft_stats.tx_packets += smb->tx_ok; + adapter->soft_stats.rx_bytes += smb->rx_byte_cnt; + adapter->soft_stats.tx_bytes += smb->tx_byte_cnt; + adapter->soft_stats.multicast += smb->rx_mcast; + adapter->soft_stats.collisions += (smb->tx_1_col + + smb->tx_2_col * 2 + + smb->tx_late_col + + smb->tx_abort_col * + adapter->hw.max_retry); + + /* Rx Errors */ + adapter->soft_stats.rx_errors += (smb->rx_frag + + smb->rx_fcs_err + + smb->rx_len_err + + smb->rx_sz_ov + + smb->rx_rxf_ov + + smb->rx_rrd_ov + smb->rx_align_err); + adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov; + adapter->soft_stats.rx_length_errors += smb->rx_len_err; + adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err; + adapter->soft_stats.rx_frame_errors += smb->rx_align_err; + adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov + + smb->rx_rxf_ov); + + adapter->soft_stats.rx_pause += smb->rx_pause; + adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov; + adapter->soft_stats.rx_trunc += smb->rx_sz_ov; + + /* Tx Errors */ + adapter->soft_stats.tx_errors += (smb->tx_late_col + + smb->tx_abort_col + + smb->tx_underrun + smb->tx_trunc); + adapter->soft_stats.tx_fifo_errors += smb->tx_underrun; + adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col; + adapter->soft_stats.tx_window_errors += smb->tx_late_col; + + adapter->soft_stats.excecol += smb->tx_abort_col; + adapter->soft_stats.deffer += smb->tx_defer; + adapter->soft_stats.scc += smb->tx_1_col; + adapter->soft_stats.mcc += smb->tx_2_col; + adapter->soft_stats.latecol += smb->tx_late_col; + adapter->soft_stats.tx_underun += smb->tx_underrun; + adapter->soft_stats.tx_trunc += smb->tx_trunc; + adapter->soft_stats.tx_pause += smb->tx_pause; + + adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets; + adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets; + adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes; + adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes; + adapter->net_stats.multicast = adapter->soft_stats.multicast; + adapter->net_stats.collisions = adapter->soft_stats.collisions; + adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors; + adapter->net_stats.rx_over_errors = + adapter->soft_stats.rx_missed_errors; + adapter->net_stats.rx_length_errors = + adapter->soft_stats.rx_length_errors; + adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; + adapter->net_stats.rx_frame_errors = + adapter->soft_stats.rx_frame_errors; + adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; + adapter->net_stats.rx_missed_errors = + adapter->soft_stats.rx_missed_errors; + adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors; + adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; + adapter->net_stats.tx_aborted_errors = + adapter->soft_stats.tx_aborted_errors; + adapter->net_stats.tx_window_errors = + adapter->soft_stats.tx_window_errors; + adapter->net_stats.tx_carrier_errors = + adapter->soft_stats.tx_carrier_errors; +} + +static void atl1_rx_checksum(struct atl1_adapter *adapter, + struct rx_return_desc *rrd, + struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + + if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { + if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC | + ERR_FLAG_CODE | ERR_FLAG_OV)) { + adapter->hw_csum_err++; + printk(KERN_DEBUG "%s: rx checksum error\n", + atl1_driver_name); + return; + } + } + + /* not IPv4 */ + if (!(rrd->pkt_flg & PACKET_FLAG_IPV4)) + /* checksum is invalid, but it's not an IPv4 pkt, so ok */ + return; + + /* IPv4 packet */ + if (likely(!(rrd->err_flg & + (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_good++; + return; + } + + /* IPv4, but hardware thinks its checksum is wrong */ + printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n", + atl1_driver_name, rrd->pkt_flg, rrd->err_flg); + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum); + adapter->hw_csum_err++; + return; +} + +/* + * atl1_alloc_rx_buffers - Replace used receive buffers + * @adapter: address of board private structure + */ +static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) +{ + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct page *page; + unsigned long offset; + struct atl1_buffer *buffer_info, *next_info; + struct sk_buff *skb; + u16 num_alloc = 0; + u16 rfd_next_to_use, next_next; + struct rx_free_desc *rfd_desc; + + next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use); + if (++next_next == rfd_ring->count) + next_next = 0; + buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; + next_info = &rfd_ring->buffer_info[next_next]; + + while (!buffer_info->alloced && !next_info->alloced) { + if (buffer_info->skb) { + buffer_info->alloced = 1; + goto next; + } + + rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use); + + skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); + if (unlikely(!skb)) { /* Better luck next round */ + adapter->net_stats.rx_dropped++; + break; + } + + /* + * Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + skb->dev = netdev; + + buffer_info->alloced = 1; + buffer_info->skb = skb; + buffer_info->length = (u16) adapter->rx_buffer_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(pdev, page, offset, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len); + rfd_desc->coalese = 0; + +next: + rfd_next_to_use = next_next; + if (unlikely(++next_next == rfd_ring->count)) + next_next = 0; + + buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; + next_info = &rfd_ring->buffer_info[next_next]; + num_alloc++; + } + + if (num_alloc) { + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use); + } + return num_alloc; +} + +static void atl1_intr_rx(struct atl1_adapter *adapter) +{ + int i, count; + u16 length; + u16 rrd_next_to_clean; + u32 value; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_buffer *buffer_info; + struct rx_return_desc *rrd; + struct sk_buff *skb; + + count = 0; + + rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean); + + while (1) { + rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean); + i = 1; + if (likely(rrd->xsz.valid)) { /* packet valid */ +chk_rrd: + /* check rrd status */ + if (likely(rrd->num_buf == 1)) + goto rrd_ok; + + /* rrd seems to be bad */ + if (unlikely(i-- > 0)) { + /* rrd may not be DMAed completely */ + printk(KERN_DEBUG + "%s: RRD may not be DMAed completely\n", + atl1_driver_name); + udelay(1); + goto chk_rrd; + } + /* bad rrd */ + printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name); + /* see if update RFD index */ + if (rrd->num_buf > 1) { + u16 num_buf; + num_buf = + (rrd->xsz.xsum_sz.pkt_size + + adapter->rx_buffer_len - + 1) / adapter->rx_buffer_len; + if (rrd->num_buf == num_buf) { + /* clean alloc flag for bad rrd */ + while (rfd_ring->next_to_clean != + (rrd->buf_indx + num_buf)) { + rfd_ring->buffer_info[rfd_ring-> + next_to_clean].alloced = 0; + if (++rfd_ring->next_to_clean == + rfd_ring->count) { + rfd_ring-> + next_to_clean = 0; + } + } + } + } + + /* update rrd */ + rrd->xsz.valid = 0; + if (++rrd_next_to_clean == rrd_ring->count) + rrd_next_to_clean = 0; + count++; + continue; + } else { /* current rrd still not be updated */ + + break; + } +rrd_ok: + /* clean alloc flag for bad rrd */ + while (rfd_ring->next_to_clean != rrd->buf_indx) { + rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced = + 0; + if (++rfd_ring->next_to_clean == rfd_ring->count) + rfd_ring->next_to_clean = 0; + } + + buffer_info = &rfd_ring->buffer_info[rrd->buf_indx]; + if (++rfd_ring->next_to_clean == rfd_ring->count) + rfd_ring->next_to_clean = 0; + + /* update rrd next to clean */ + if (++rrd_next_to_clean == rrd_ring->count) + rrd_next_to_clean = 0; + count++; + + if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { + if (!(rrd->err_flg & + (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM + | ERR_FLAG_LEN))) { + /* packet error, don't need upstream */ + buffer_info->alloced = 0; + rrd->xsz.valid = 0; + continue; + } + } + + /* Good Receive */ + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_FROMDEVICE); + skb = buffer_info->skb; + length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size); + + skb_put(skb, length - ETHERNET_FCS_SIZE); + + /* Receive Checksum Offload */ + atl1_rx_checksum(adapter, rrd, skb); + skb->protocol = eth_type_trans(skb, adapter->netdev); + + if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) { + u16 vlan_tag = (rrd->vlan_tag >> 4) | + ((rrd->vlan_tag & 7) << 13) | + ((rrd->vlan_tag & 8) << 9); + vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag); + } else + netif_rx(skb); + + /* let protocol layer free skb */ + buffer_info->skb = NULL; + buffer_info->alloced = 0; + rrd->xsz.valid = 0; + + adapter->netdev->last_rx = jiffies; + } + + atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean); + + atl1_alloc_rx_buffers(adapter); + + /* update mailbox ? */ + if (count) { + u32 tpd_next_to_use; + u32 rfd_next_to_use; + u32 rrd_next_to_clean; + + spin_lock(&adapter->mb_lock); + + tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use); + rfd_next_to_use = + atomic_read(&adapter->rfd_ring.next_to_use); + rrd_next_to_clean = + atomic_read(&adapter->rrd_ring.next_to_clean); + value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) << + MB_RFD_PROD_INDX_SHIFT) | + ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) << + MB_RRD_CONS_INDX_SHIFT) | + ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) << + MB_TPD_PROD_INDX_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); + spin_unlock(&adapter->mb_lock); + } +} + +static void atl1_intr_tx(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + u16 sw_tpd_next_to_clean; + u16 cmb_tpd_next_to_clean; + u8 update = 0; + + sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean); + cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx); + + while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) { + struct tx_packet_desc *tpd; + update = 1; + tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean); + buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean]; + if (buffer_info->dma) { + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + + if (buffer_info->skb) { + dev_kfree_skb_irq(buffer_info->skb); + buffer_info->skb = NULL; + } + tpd->buffer_addr = 0; + tpd->desc.data = 0; + + if (++sw_tpd_next_to_clean == tpd_ring->count) + sw_tpd_next_to_clean = 0; + } + atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean); + + if (netif_queue_stopped(adapter->netdev) + && netif_carrier_ok(adapter->netdev)) + netif_wake_queue(adapter->netdev); +} + +static void atl1_check_for_link(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 phy_data = 0; + + spin_lock(&adapter->lock); + adapter->phy_timer_pending = false; + atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + spin_unlock(&adapter->lock); + + /* notify upper layer link down ASAP */ + if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + printk(KERN_INFO "%s: %s link is down\n", + atl1_driver_name, netdev->name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + schedule_work(&adapter->link_chg_task); +} + +/* + * atl1_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + */ +static irqreturn_t atl1_intr(int irq, void *data) +{ + /*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/ + struct atl1_adapter *adapter = netdev_priv(data); + u32 status; + u8 update_rx; + int max_ints = 10; + + status = adapter->cmb.cmb->int_stats; + if (!status) + return IRQ_NONE; + + update_rx = 0; + + do { + /* clear CMB interrupt status at once */ + adapter->cmb.cmb->int_stats = 0; + + if (status & ISR_GPHY) /* clear phy status */ + atl1_clear_phy_int(adapter); + + /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ + iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR); + + /* check if SMB intr */ + if (status & ISR_SMB) + atl1_inc_smb(adapter); + + /* check if PCIE PHY Link down */ + if (status & ISR_PHY_LINKDOWN) { + printk(KERN_DEBUG "%s: pcie phy link down %x\n", + atl1_driver_name, status); + if (netif_running(adapter->netdev)) { /* reset MAC */ + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + schedule_work(&adapter->pcie_dma_to_rst_task); + return IRQ_HANDLED; + } + } + + /* check if DMA read/write error ? */ + if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { + printk(KERN_DEBUG + "%s: pcie DMA r/w error (status = 0x%x)\n", + atl1_driver_name, status); + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + schedule_work(&adapter->pcie_dma_to_rst_task); + return IRQ_HANDLED; + } + + /* link event */ + if (status & ISR_GPHY) { + adapter->soft_stats.tx_carrier_errors++; + atl1_check_for_link(adapter); + } + + /* transmit event */ + if (status & ISR_CMB_TX) + atl1_intr_tx(adapter); + + /* rx exception */ + if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN | + ISR_RRD_OV | ISR_HOST_RFD_UNRUN | + ISR_HOST_RRD_OV | ISR_CMB_RX))) { + if (status & + (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV | + ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV)) + printk(KERN_INFO + "%s: rx exception: status = 0x%x\n", + atl1_driver_name, status); + atl1_intr_rx(adapter); + } + + if (--max_ints < 0) + break; + + } while ((status = adapter->cmb.cmb->int_stats)); + + /* re-enable Interrupt */ + iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR); + return IRQ_HANDLED; +} + +/* + * atl1_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + */ +static void atl1_set_multi(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + struct dev_mc_list *mc_ptr; + u32 rctl; + u32 hash_value; + + /* Check for Promiscuous and All Multicast modes */ + rctl = ioread32(hw->hw_addr + REG_MAC_CTRL); + if (netdev->flags & IFF_PROMISC) + rctl |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) { + rctl |= MAC_CTRL_MC_ALL_EN; + rctl &= ~MAC_CTRL_PROMIS_EN; + } else + rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN); + + iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL); + + /* clear the old settings from the multicast hash table */ + iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE); + iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2)); + + /* compute mc addresses' hash value ,and put it into hash table */ + for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr); + atl1_hash_set(hw, hash_value); + } +} + +static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter) +{ + u32 value; + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + /* Config MAC CTRL Register */ + value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; + /* duplex */ + if (FULL_DUPLEX == adapter->link_duplex) + value |= MAC_CTRL_DUPLX; + /* speed */ + value |= ((u32) ((SPEED_1000 == adapter->link_speed) ? + MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) << + MAC_CTRL_SPEED_SHIFT); + /* flow control */ + value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); + /* PAD & CRC */ + value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); + /* preamble length */ + value |= (((u32) adapter->hw.preamble_len + & MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); + /* vlan */ + if (adapter->vlgrp) + value |= MAC_CTRL_RMV_VLAN; + /* rx checksum + if (adapter->rx_csum) + value |= MAC_CTRL_RX_CHKSUM_EN; + */ + /* filter mode */ + value |= MAC_CTRL_BC_EN; + if (netdev->flags & IFF_PROMISC) + value |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) + value |= MAC_CTRL_MC_ALL_EN; + /* value |= MAC_CTRL_LOOPBACK; */ + iowrite32(value, hw->hw_addr + REG_MAC_CTRL); +} + +static u32 atl1_check_link(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + u32 ret_val; + u16 speed, duplex, phy_data; + int reconfig = 0; + + /* MII_BMSR must read twice */ + atl1_read_phy_reg(hw, MII_BMSR, &phy_data); + atl1_read_phy_reg(hw, MII_BMSR, &phy_data); + if (!(phy_data & BMSR_LSTATUS)) { /* link down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + printk(KERN_INFO "%s: link is down\n", + atl1_driver_name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + return ATL1_SUCCESS; + } + + /* Link Up */ + ret_val = atl1_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) + return ret_val; + + switch (hw->media_type) { + case MEDIA_TYPE_1000M_FULL: + if (speed != SPEED_1000 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_FULL: + if (speed != SPEED_100 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_HALF: + if (speed != SPEED_100 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_FULL: + if (speed != SPEED_10 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_HALF: + if (speed != SPEED_10 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + } + + /* link result is our setting */ + if (!reconfig) { + if (adapter->link_speed != speed + || adapter->link_duplex != duplex) { + adapter->link_speed = speed; + adapter->link_duplex = duplex; + atl1_setup_mac_ctrl(adapter); + printk(KERN_INFO "%s: %s link is up %d Mbps %s\n", + atl1_driver_name, netdev->name, + adapter->link_speed, + adapter->link_duplex == + FULL_DUPLEX ? "full duplex" : "half duplex"); + } + if (!netif_carrier_ok(netdev)) { /* Link down -> Up */ + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } + return ATL1_SUCCESS; + } + + /* change orignal link status */ + if (netif_carrier_ok(netdev)) { + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + + if (hw->media_type != MEDIA_TYPE_AUTO_SENSOR && + hw->media_type != MEDIA_TYPE_1000M_FULL) { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); + return ATL1_SUCCESS; + } + + /* auto-neg, insert timer to re-config phy */ + if (!adapter->phy_timer_pending) { + adapter->phy_timer_pending = true; + mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ); + } + + return ATL1_SUCCESS; +} + +static void set_flow_ctrl_old(struct atl1_adapter *adapter) +{ + u32 hi, lo, value; + + /* RFD Flow Control */ + value = adapter->rfd_ring.count; + hi = value / 16; + if (hi < 2) + hi = 2; + lo = value * 7 / 8; + + value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH); + + /* RRD Flow Control */ + value = adapter->rrd_ring.count; + lo = value / 16; + hi = value * 7 / 8; + if (lo < 2) + lo = 2; + value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH); +} + +static void set_flow_ctrl_new(struct atl1_hw *hw) +{ + u32 hi, lo, value; + + /* RXF Flow Control */ + value = ioread32(hw->hw_addr + REG_SRAM_RXF_LEN); + lo = value / 16; + if (lo < 192) + lo = 192; + hi = value * 7 / 8; + if (hi < lo) + hi = lo + 16; + value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH); + + /* RRD Flow Control */ + value = ioread32(hw->hw_addr + REG_SRAM_RRD_LEN); + lo = value / 8; + hi = value * 7 / 8; + if (lo < 2) + lo = 2; + if (hi < lo) + hi = lo + 3; + value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH); +} + +/* + * atl1_configure - Configure Transmit&Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Tx /Rx unit of the MAC after a reset. + */ +static u32 atl1_configure(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + u32 value; + + /* clear interrupt status */ + iowrite32(0xffffffff, adapter->hw.hw_addr + REG_ISR); + + /* set MAC Address */ + value = (((u32) hw->mac_addr[2]) << 24) | + (((u32) hw->mac_addr[3]) << 16) | + (((u32) hw->mac_addr[4]) << 8) | + (((u32) hw->mac_addr[5])); + iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR); + value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1])); + iowrite32(value, hw->hw_addr + (REG_MAC_STA_ADDR + 4)); + + /* tx / rx ring */ + + /* HI base address */ + iowrite32((u32) ((adapter->tpd_ring.dma & 0xffffffff00000000ULL) >> 32), + hw->hw_addr + REG_DESC_BASE_ADDR_HI); + /* LO base address */ + iowrite32((u32) (adapter->rfd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_RFD_ADDR_LO); + iowrite32((u32) (adapter->rrd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_RRD_ADDR_LO); + iowrite32((u32) (adapter->tpd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_TPD_ADDR_LO); + iowrite32((u32) (adapter->cmb.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_CMB_ADDR_LO); + iowrite32((u32) (adapter->smb.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_SMB_ADDR_LO); + + /* element count */ + value = adapter->rrd_ring.count; + value <<= 16; + value += adapter->rfd_ring.count; + iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE); + iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE); + + /* Load Ptr */ + iowrite32(1, hw->hw_addr + REG_LOAD_PTR); + + /* config Mailbox */ + value = ((atomic_read(&adapter->tpd_ring.next_to_use) + & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) | + ((atomic_read(&adapter->rrd_ring.next_to_clean) + & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) | + ((atomic_read(&adapter->rfd_ring.next_to_use) + & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAILBOX); + + /* config IPG/IFG */ + value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK) + << MAC_IPG_IFG_IPGT_SHIFT) | + (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) + << MAC_IPG_IFG_MIFG_SHIFT) | + (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) + << MAC_IPG_IFG_IPGR1_SHIFT) | + (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) + << MAC_IPG_IFG_IPGR2_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG); + + /* config Half-Duplex Control */ + value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) | + (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK) + << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) | + MAC_HALF_DUPLX_CTRL_EXC_DEF_EN | + (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) | + (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) + << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL); + + /* set Interrupt Moderator Timer */ + iowrite16(adapter->imt, hw->hw_addr + REG_IRQ_MODU_TIMER_INIT); + iowrite32(MASTER_CTRL_ITIMER_EN, hw->hw_addr + REG_MASTER_CTRL); + + /* set Interrupt Clear Timer */ + iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER); + + /* set MTU, 4 : VLAN */ + iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU); + + /* jumbo size & rrd retirement timer */ + value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK) + << RXQ_JMBOSZ_TH_SHIFT) | + (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK) + << RXQ_JMBO_LKAH_SHIFT) | + (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK) + << RXQ_RRD_TIMER_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM); + + /* Flow Control */ + switch (hw->dev_rev) { + case 0x8001: + case 0x9001: + case 0x9002: + case 0x9003: + set_flow_ctrl_old(adapter); + break; + default: + set_flow_ctrl_new(hw); + break; + } + + /* config TXQ */ + value = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK) + << TXQ_CTRL_TPD_BURST_NUM_SHIFT) | + (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK) + << TXQ_CTRL_TXF_BURST_NUM_SHIFT) | + (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK) + << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN; + iowrite32(value, hw->hw_addr + REG_TXQ_CTRL); + + /* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */ + value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK) + << TX_JUMBO_TASK_TH_SHIFT) | + (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK) + << TX_TPD_MIN_IPG_SHIFT); + iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG); + + /* config RXQ */ + value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK) + << RXQ_CTRL_RFD_BURST_NUM_SHIFT) | + (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK) + << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) | + (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK) + << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) | + RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN; + iowrite32(value, hw->hw_addr + REG_RXQ_CTRL); + + /* config DMA Engine */ + value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) + << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | + ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) + << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | + DMA_CTRL_DMAR_EN | DMA_CTRL_DMAW_EN; + value |= (u32) hw->dma_ord; + if (atl1_rcb_128 == hw->rcb_value) + value |= DMA_CTRL_RCB_VALUE; + iowrite32(value, hw->hw_addr + REG_DMA_CTRL); + + /* config CMB / SMB */ + value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16); + iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH); + value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16); + iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER); + iowrite32(hw->smb_timer, hw->hw_addr + REG_SMB_TIMER); + + /* --- enable CMB / SMB */ + value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN; + iowrite32(value, hw->hw_addr + REG_CSMB_CTRL); + + value = ioread32(adapter->hw.hw_addr + REG_ISR); + if (unlikely((value & ISR_PHY_LINKDOWN) != 0)) + value = 1; /* config failed */ + else + value = 0; + + /* clear all interrupt status */ + iowrite32(0x3fffffff, adapter->hw.hw_addr + REG_ISR); + iowrite32(0, adapter->hw.hw_addr + REG_ISR); + return value; +} + +/* + * atl1_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + */ +static void atl1_irq_disable(struct atl1_adapter *adapter) +{ + atomic_inc(&adapter->irq_sem); + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + ioread32(adapter->hw.hw_addr + REG_IMR); + synchronize_irq(adapter->pdev->irq); +} + +static void atl1_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(&adapter->lock, flags); + /* atl1_irq_disable(adapter); */ + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); + ctrl |= MAC_CTRL_RMV_VLAN; + iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); + } else { + /* disable VLAN tag insert/strip */ + ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_RMV_VLAN; + iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); + } + + /* atl1_irq_enable(adapter); */ + spin_unlock_irqrestore(&adapter->lock, flags); +} + +/* FIXME: justify or remove -- CHS */ +static void atl1_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + /* We don't do Vlan filtering */ + return; +} + +/* FIXME: this looks wrong too -- CHS */ +static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + /* atl1_irq_disable(adapter); */ + if (adapter->vlgrp) + adapter->vlgrp->vlan_devices[vid] = NULL; + /* atl1_irq_enable(adapter); */ + spin_unlock_irqrestore(&adapter->lock, flags); + /* We don't do Vlan filtering */ + return; +} + +static void atl1_restore_vlan(struct atl1_adapter *adapter) +{ + atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp); + if (adapter->vlgrp) { + u16 vid; + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!adapter->vlgrp->vlan_devices[vid]) + continue; + atl1_vlan_rx_add_vid(adapter->netdev, vid); + } + } +} + +static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring) +{ + u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean); + u16 next_to_use = atomic_read(&tpd_ring->next_to_use); + return ((next_to_clean > + next_to_use) ? next_to_clean - next_to_use - + 1 : tpd_ring->count + next_to_clean - next_to_use - 1); +} + +static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, + struct tso_param *tso) +{ + /* We enter this function holding a spinlock. */ + u8 ipofst; + int err; + + if (skb_shinfo(skb)->gso_size) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (unlikely(err)) + return err; + } + + if (skb->protocol == ntohs(ETH_P_IP)) { + skb->nh.iph->tot_len = 0; + skb->nh.iph->check = 0; + skb->h.th->check = + ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, 0, + IPPROTO_TCP, 0); + ipofst = skb->nh.raw - skb->data; + if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */ + tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT; + + tso->tsopl |= (skb->nh.iph->ihl & + CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT; + tso->tsopl |= ((skb->h.th->doff << 2) & + TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT; + tso->tsopl |= (skb_shinfo(skb)->gso_size & + TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_IPCKSUM_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_TCPCKSUM_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_SEGMENT_SHIFT; + return true; + } + } + return false; +} + +static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb, + struct csum_param *csum) +{ + u8 css, cso; + + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { + cso = skb->h.raw - skb->data; + css = (skb->h.raw + skb->csum) - skb->data; + if (unlikely(cso & 0x1)) { + printk(KERN_DEBUG "%s: payload offset != even number\n", + atl1_driver_name); + return -1; + } + csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) << + CSUM_PARAM_PLOADOFFSET_SHIFT; + csum->csumpl |= (css & CSUM_PARAM_XSUMOFFSET_MASK) << + CSUM_PARAM_XSUMOFFSET_SHIFT; + csum->csumpl |= 1 << CSUM_PARAM_CUSTOMCKSUM_SHIFT; + return true; + } + + return true; +} + +static void atl1_tx_map(struct atl1_adapter *adapter, + struct sk_buff *skb, bool tcp_seg) +{ + /* We enter this function holding a spinlock. */ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + struct page *page; + int first_buf_len = skb->len; + unsigned long offset; + unsigned int nr_frags; + unsigned int f; + u16 tpd_next_to_use; + u16 proto_hdr_len; + u16 i, m, len12; + + first_buf_len -= skb->data_len; + nr_frags = skb_shinfo(skb)->nr_frags; + tpd_next_to_use = atomic_read(&tpd_ring->next_to_use); + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + if (unlikely(buffer_info->skb)) + BUG(); + buffer_info->skb = NULL; /* put skb in last TPD */ + + if (tcp_seg) { + /* TSO/GSO */ + proto_hdr_len = + ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + buffer_info->length = proto_hdr_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(adapter->pdev, page, + offset, proto_hdr_len, + PCI_DMA_TODEVICE); + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + + if (first_buf_len > proto_hdr_len) { + len12 = first_buf_len - proto_hdr_len; + m = (len12 + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + for (i = 0; i < m; i++) { + buffer_info = + &tpd_ring->buffer_info[tpd_next_to_use]; + buffer_info->skb = NULL; + buffer_info->length = + (MAX_TX_BUF_LEN >= + len12) ? MAX_TX_BUF_LEN : len12; + len12 -= buffer_info->length; + page = virt_to_page(skb->data + + (proto_hdr_len + + i * MAX_TX_BUF_LEN)); + offset = (unsigned long)(skb->data + + (proto_hdr_len + + i * MAX_TX_BUF_LEN)) & + ~PAGE_MASK; + buffer_info->dma = + pci_map_page(adapter->pdev, page, offset, + buffer_info->length, + PCI_DMA_TODEVICE); + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + } + } else { + /* not TSO/GSO */ + buffer_info->length = first_buf_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(adapter->pdev, page, + offset, first_buf_len, + PCI_DMA_TODEVICE); + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + u16 lenf, i, m; + + frag = &skb_shinfo(skb)->frags[f]; + lenf = frag->size; + + m = (lenf + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + for (i = 0; i < m; i++) { + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + if (unlikely(buffer_info->skb)) + BUG(); + buffer_info->skb = NULL; + buffer_info->length = + (lenf > MAX_TX_BUF_LEN) ? MAX_TX_BUF_LEN : lenf; + lenf -= buffer_info->length; + buffer_info->dma = + pci_map_page(adapter->pdev, frag->page, + frag->page_offset + i * MAX_TX_BUF_LEN, + buffer_info->length, PCI_DMA_TODEVICE); + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + } + + /* last tpd's buffer-info */ + buffer_info->skb = skb; +} + +static void atl1_tx_queue(struct atl1_adapter *adapter, int count, + union tpd_descr *descr) +{ + /* We enter this function holding a spinlock. */ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + int j; + u32 val; + struct atl1_buffer *buffer_info; + struct tx_packet_desc *tpd; + u16 tpd_next_to_use = atomic_read(&tpd_ring->next_to_use); + + for (j = 0; j < count; j++) { + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + tpd = ATL1_TPD_DESC(&adapter->tpd_ring, tpd_next_to_use); + tpd->desc.csum.csumpu = descr->csum.csumpu; + tpd->desc.csum.csumpl = descr->csum.csumpl; + tpd->desc.tso.tsopu = descr->tso.tsopu; + tpd->desc.tso.tsopl = descr->tso.tsopl; + tpd->buffer_addr = cpu_to_le64(buffer_info->dma); + tpd->desc.data = descr->data; + tpd->desc.csum.csumpu |= (cpu_to_le16(buffer_info->length) & + CSUM_PARAM_BUFLEN_MASK) << CSUM_PARAM_BUFLEN_SHIFT; + + val = (descr->tso.tsopl >> TSO_PARAM_SEGMENT_SHIFT) & + TSO_PARAM_SEGMENT_MASK; + if (val && !j) + tpd->desc.tso.tsopl |= 1 << TSO_PARAM_HDRFLAG_SHIFT; + + if (j == (count - 1)) + tpd->desc.csum.csumpl |= 1 << CSUM_PARAM_EOP_SHIFT; + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + + atomic_set(&tpd_ring->next_to_use, (int)tpd_next_to_use); +} + +static void atl1_update_mailbox(struct atl1_adapter *adapter) +{ + unsigned long flags; + u32 tpd_next_to_use; + u32 rfd_next_to_use; + u32 rrd_next_to_clean; + u32 value; + + spin_lock_irqsave(&adapter->mb_lock, flags); + + tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use); + rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use); + rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean); + + value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) << + MB_RFD_PROD_INDX_SHIFT) | + ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) << + MB_RRD_CONS_INDX_SHIFT) | + ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) << + MB_TPD_PROD_INDX_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); + + spin_unlock_irqrestore(&adapter->mb_lock, flags); +} + +static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int len = skb->len; + int tso; + int count = 1; + int ret_val; + u32 val; + union tpd_descr param; + u16 frag_size; + u16 vlan_tag; + unsigned long flags; + unsigned int nr_frags = 0; + unsigned int mss = 0; + unsigned int f; + unsigned int proto_hdr_len; + + len -= skb->data_len; + + if (unlikely(skb->len == 0)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + param.data = 0; + param.tso.tsopu = 0; + param.tso.tsopl = 0; + param.csum.csumpu = 0; + param.csum.csumpl = 0; + + /* nr_frags will be nonzero if we're doing scatter/gather (SG) */ + nr_frags = skb_shinfo(skb)->nr_frags; + for (f = 0; f < nr_frags; f++) { + frag_size = skb_shinfo(skb)->frags[f].size; + if (frag_size) + count += + (frag_size + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + } + + /* mss will be nonzero if we're doing segment offload (TSO/GSO) */ + mss = skb_shinfo(skb)->gso_size; + if (mss) { + if (skb->protocol == ntohs(ETH_P_IP)) { + proto_hdr_len = ((skb->h.raw - skb->data) + + (skb->h.th->doff << 2)); + if (unlikely(proto_hdr_len > len)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + /* need additional TPD ? */ + if (proto_hdr_len != len) + count += (len - proto_hdr_len + + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + } + } + + local_irq_save(flags); + if (!spin_trylock(&adapter->lock)) { + /* Can't get lock - tell upper layer to requeue */ + local_irq_restore(flags); + printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name); + return NETDEV_TX_LOCKED; + } + + if (tpd_avail(&adapter->tpd_ring) < count) { + /* not enough descriptors */ + netif_stop_queue(netdev); + spin_unlock_irqrestore(&adapter->lock, flags); + printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name); + return NETDEV_TX_BUSY; + } + + param.data = 0; + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) | + ((vlan_tag >> 9) & 0x8); + param.csum.csumpl |= 1 << CSUM_PARAM_INSVLAG_SHIFT; + param.csum.csumpu |= (vlan_tag & CSUM_PARAM_VALANTAG_MASK) << + CSUM_PARAM_VALAN_SHIFT; + } + + tso = atl1_tso(adapter, skb, ¶m.tso); + if (tso < 0) { + spin_unlock_irqrestore(&adapter->lock, flags); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (!tso) { + ret_val = atl1_tx_csum(adapter, skb, ¶m.csum); + if (ret_val < 0) { + spin_unlock_irqrestore(&adapter->lock, flags); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + } + + val = (param.csum.csumpl >> CSUM_PARAM_SEGMENT_SHIFT) & + CSUM_PARAM_SEGMENT_MASK; + atl1_tx_map(adapter, skb, 1 == val); + atl1_tx_queue(adapter, count, ¶m); + netdev->trans_start = jiffies; + spin_unlock_irqrestore(&adapter->lock, flags); + atl1_update_mailbox(adapter); + return NETDEV_TX_OK; +} + +/* + * atl1_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + */ +static struct net_device_stats *atl1_get_stats(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + return &adapter->net_stats; +} + +/* + * atl1_clean_rx_ring - Free RFD Buffers + * @adapter: board private structure + */ +static void atl1_clean_rx_ring(struct atl1_adapter *adapter) +{ + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Rx ring sk_buffs */ + for (i = 0; i < rfd_ring->count; i++) { + buffer_info = &rfd_ring->buffer_info[i]; + if (buffer_info->dma) { + pci_unmap_page(pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + } + if (buffer_info->skb) { + dev_kfree_skb(buffer_info->skb); + buffer_info->skb = NULL; + } + } + + size = sizeof(struct atl1_buffer) * rfd_ring->count; + memset(rfd_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(rfd_ring->desc, 0, rfd_ring->size); + + rfd_ring->next_to_clean = 0; + atomic_set(&rfd_ring->next_to_use, 0); + + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); +} + +/* + * atl1_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + */ +static void atl1_clean_tx_ring(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Tx ring sk_buffs */ + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; + if (buffer_info->dma) { + pci_unmap_page(pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + } + + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; + if (buffer_info->skb) { + dev_kfree_skb_any(buffer_info->skb); + buffer_info->skb = NULL; + } + } + + size = sizeof(struct atl1_buffer) * tpd_ring->count; + memset(tpd_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(tpd_ring->desc, 0, tpd_ring->size); + + atomic_set(&tpd_ring->next_to_use, 0); + atomic_set(&tpd_ring->next_to_clean, 0); +} + +/* + * atl1_free_ring_resources - Free Tx / RX descriptor Resources + * @adapter: board private structure + * + * Free all transmit software resources + */ +void atl1_free_ring_resources(struct atl1_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_ring_header *ring_header = &adapter->ring_header; + + atl1_clean_tx_ring(adapter); + atl1_clean_rx_ring(adapter); + + kfree(tpd_ring->buffer_info); + pci_free_consistent(pdev, ring_header->size, ring_header->desc, + ring_header->dma); + + tpd_ring->buffer_info = NULL; + tpd_ring->desc = NULL; + tpd_ring->dma = 0; + + rfd_ring->buffer_info = NULL; + rfd_ring->desc = NULL; + rfd_ring->dma = 0; + + rrd_ring->desc = NULL; + rrd_ring->dma = 0; +} + +s32 atl1_up(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int err; + int irq_flags = IRQF_SAMPLE_RANDOM; + + /* hardware has been reset, we need to reload some things */ + atl1_set_multi(netdev); + atl1_restore_vlan(adapter); + err = atl1_alloc_rx_buffers(adapter); + if (unlikely(!err)) /* no RX BUFFER allocated */ + return -ENOMEM; + + if (unlikely(atl1_configure(adapter))) { + err = -EIO; + goto err_up; + } + + err = pci_enable_msi(adapter->pdev); + if (err) { + dev_info(&adapter->pdev->dev, + "Unable to enable MSI: %d\n", err); + irq_flags |= IRQF_SHARED; + } + + err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags, + netdev->name, netdev); + if (unlikely(err)) + goto err_up; + + mod_timer(&adapter->watchdog_timer, jiffies); + atl1_irq_enable(adapter); + atl1_check_link(adapter); + return 0; + + /* FIXME: unreachable code! -- CHS */ + /* free irq disable any interrupt */ + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + free_irq(adapter->pdev->irq, netdev); + +err_up: + pci_disable_msi(adapter->pdev); + /* free rx_buffers */ + atl1_clean_rx_ring(adapter); + return err; +} + +void atl1_down(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_config_timer); + adapter->phy_timer_pending = false; + + atl1_irq_disable(adapter); + free_irq(adapter->pdev->irq, netdev); + pci_disable_msi(adapter->pdev); + atl1_reset_hw(&adapter->hw); + adapter->cmb.cmb->int_stats = 0; + + adapter->link_speed = SPEED_0; + adapter->link_duplex = -1; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + atl1_clean_tx_ring(adapter); + atl1_clean_rx_ring(adapter); +} + +/* + * atl1_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + */ +static int atl1_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int old_mtu = netdev->mtu; + int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + + if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || + (max_frame > MAX_JUMBO_FRAME_SIZE)) { + printk(KERN_WARNING "%s: invalid MTU setting\n", + atl1_driver_name); + return -EINVAL; + } + + adapter->hw.max_frame_size = max_frame; + adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3; + adapter->rx_buffer_len = (max_frame + 7) & ~7; + adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8; + + netdev->mtu = new_mtu; + if ((old_mtu != new_mtu) && netif_running(netdev)) { + atl1_down(adapter); + atl1_up(adapter); + } + + return 0; +} + +/* + * atl1_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + */ +static int atl1_set_mac(struct net_device *netdev, void *p) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (netif_running(netdev)) + return -EBUSY; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); + + atl1_set_mac_addr(&adapter->hw); + return 0; +} + +/* + * atl1_watchdog - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl1_watchdog(unsigned long data) +{ + struct atl1_adapter *adapter = (struct atl1_adapter *)data; + + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); +} + +static int mdio_read(struct net_device *netdev, int phy_id, int reg_num) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + u16 result; + + atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result); + + return result; +} + +static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, int val) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + atl1_write_phy_reg(&adapter->hw, reg_num, val); +} + +/* + * atl1_mii_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + int retval; + + if (!netif_running(netdev)) + return -EINVAL; + + spin_lock_irqsave(&adapter->lock, flags); + retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL); + spin_unlock_irqrestore(&adapter->lock, flags); + + return retval; +} + +/* + * atl1_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return atl1_mii_ioctl(netdev, ifr, cmd); + default: + return -EOPNOTSUPP; + } +} + +/* + * atl1_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + */ +static void atl1_tx_timeout(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->tx_timeout_task); +} + +/* + * atl1_phy_config - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl1_phy_config(unsigned long data) +{ + struct atl1_adapter *adapter = (struct atl1_adapter *)data; + struct atl1_hw *hw = &adapter->hw; + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + adapter->phy_timer_pending = false; + atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); + atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg); + atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +int atl1_reset(struct atl1_adapter *adapter) +{ + int ret; + + ret = atl1_reset_hw(&adapter->hw); + if (ret != ATL1_SUCCESS) + return ret; + return atl1_init_hw(&adapter->hw); +} + +/* + * atl1_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + */ +static int atl1_open(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int err; + + /* allocate transmit descriptors */ + err = atl1_setup_ring_resources(adapter); + if (err) + return err; + + err = atl1_up(adapter); + if (err) + goto err_up; + + return 0; + +err_up: + atl1_reset(adapter); + return err; +} + +/* + * atl1_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + */ +static int atl1_close(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + atl1_down(adapter); + atl1_free_ring_resources(adapter); + return 0; +} + +/* + * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT + * will assert. We do soft reset <0x1400=1> according + * with the SPEC. BUT, it seemes that PCIE or DMA + * state-machine will not be reset. DMAR_TO_INT will + * assert again and again. + */ +static void atl1_tx_timeout_task(struct work_struct *work) +{ + struct atl1_adapter *adapter = + container_of(work, struct atl1_adapter, tx_timeout_task); + struct net_device *netdev = adapter->netdev; + + netif_device_detach(netdev); + atl1_down(adapter); + atl1_up(adapter); + netif_device_attach(netdev); +} + +/* + * atl1_link_chg_task - deal with link change event Out of interrupt context + */ +static void atl1_link_chg_task(struct work_struct *work) +{ + struct atl1_adapter *adapter = + container_of(work, struct atl1_adapter, link_chg_task); + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + atl1_check_link(adapter); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +/* + * atl1_pcie_patch - Patch for PCIE module + */ +static void atl1_pcie_patch(struct atl1_adapter *adapter) +{ + u32 value; + value = 0x6500; + iowrite32(value, adapter->hw.hw_addr + 0x12FC); + /* pcie flow control mode change */ + value = ioread32(adapter->hw.hw_addr + 0x1008); + value |= 0x8000; + iowrite32(value, adapter->hw.hw_addr + 0x1008); +} + +/* + * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400 + * on PCI Command register is disable. + * The function enable this bit. + * Brackett, 2006/03/15 + */ +static void atl1_via_workaround(struct atl1_adapter *adapter) +{ + unsigned long value; + + value = ioread16(adapter->hw.hw_addr + PCI_COMMAND); + if (value & PCI_COMMAND_INTX_DISABLE) + value &= ~PCI_COMMAND_INTX_DISABLE; + iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND); +} + +/* + * atl1_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in atl1_pci_tbl + * + * Returns 0 on success, negative on failure + * + * atl1_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + */ +static int __devinit atl1_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct atl1_adapter *adapter; + static int cards_found = 0; + bool pci_using_64 = true; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (err) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_DEBUG + "%s: no usable DMA configuration, aborting\n", + atl1_driver_name); + goto err_dma; + } + pci_using_64 = false; + } + /* Mark all PCI regions associated with PCI device + * pdev as being reserved by owner atl1_driver_name + */ + err = pci_request_regions(pdev, atl1_driver_name); + if (err) + goto err_request_regions; + + /* Enables bus-mastering on the device and calls + * pcibios_set_master to do the needed arch specific settings + */ + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct atl1_adapter)); + if (!netdev) { + err = -ENOMEM; + goto err_alloc_etherdev; + } + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->hw.back = adapter; + + adapter->hw.hw_addr = pci_iomap(pdev, 0, 0); + if (!adapter->hw.hw_addr) { + err = -EIO; + goto err_pci_iomap; + } + /* get device revision number */ + adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2)); + + /* set default ring resource counts */ + adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD; + adapter->tpd_ring.count = ATL1_DEFAULT_TPD; + + adapter->mii.dev = netdev; + adapter->mii.mdio_read = mdio_read; + adapter->mii.mdio_write = mdio_write; + adapter->mii.phy_id_mask = 0x1f; + adapter->mii.reg_num_mask = 0x1f; + + netdev->open = &atl1_open; + netdev->stop = &atl1_close; + netdev->hard_start_xmit = &atl1_xmit_frame; + netdev->get_stats = &atl1_get_stats; + netdev->set_multicast_list = &atl1_set_multi; + netdev->set_mac_address = &atl1_set_mac; + netdev->change_mtu = &atl1_change_mtu; + netdev->do_ioctl = &atl1_ioctl; + netdev->tx_timeout = &atl1_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netdev->vlan_rx_register = atl1_vlan_rx_register; + netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid; + netdev->ethtool_ops = &atl1_ethtool_ops; + adapter->bd_number = cards_found; + adapter->pci_using_64 = pci_using_64; + + /* setup the private structure */ + err = atl1_sw_init(adapter); + if (err) + goto err_common; + + netdev->features = NETIF_F_HW_CSUM; + netdev->features |= NETIF_F_SG; + netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); + + /* + * FIXME - Until tso performance gets fixed, disable the feature. + * Enable it with ethtool -K if desired. + */ + /* netdev->features |= NETIF_F_TSO; */ + + if (pci_using_64) + netdev->features |= NETIF_F_HIGHDMA; + + netdev->features |= NETIF_F_LLTX; + + /* + * patch for some L1 of old version, + * the final version of L1 may not need these + * patches + */ + /* atl1_pcie_patch(adapter); */ + + /* really reset GPHY core */ + iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE); + + /* + * reset the controller to + * put the device in a known good starting state + */ + if (atl1_reset_hw(&adapter->hw)) { + err = -EIO; + goto err_common; + } + + /* copy the MAC address out of the EEPROM */ + atl1_read_mac_addr(&adapter->hw); + memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->dev_addr)) { + err = -EIO; + goto err_common; + } + + atl1_check_options(adapter); + + /* pre-init the MAC, and setup link */ + err = atl1_init_hw(&adapter->hw); + if (err) { + err = -EIO; + goto err_common; + } + + atl1_pcie_patch(adapter); + /* assume we have no link for now */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &atl1_watchdog; + adapter->watchdog_timer.data = (unsigned long)adapter; + + init_timer(&adapter->phy_config_timer); + adapter->phy_config_timer.function = &atl1_phy_config; + adapter->phy_config_timer.data = (unsigned long)adapter; + adapter->phy_timer_pending = false; + + INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task); + + INIT_WORK(&adapter->link_chg_task, atl1_link_chg_task); + + INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task); + + err = register_netdev(netdev); + if (err) + goto err_common; + + cards_found++; + atl1_via_workaround(adapter); + return 0; + +err_common: + pci_iounmap(pdev, adapter->hw.hw_addr); +err_pci_iomap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_dma: +err_request_regions: + pci_disable_device(pdev); + return err; +} + +/* + * atl1_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * atl1_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + */ +static void __devexit atl1_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter; + /* Device not available. Return. */ + if (!netdev) + return; + + adapter = netdev_priv(netdev); + iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE); + unregister_netdev(netdev); + pci_iounmap(pdev, adapter->hw.hw_addr); + pci_release_regions(pdev); + free_netdev(netdev); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int atl1_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + u32 ctrl = 0; + u32 wufc = adapter->wol; + + netif_device_detach(netdev); + if (netif_running(netdev)) + atl1_down(adapter); + + atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); + atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); + if (ctrl & BMSR_LSTATUS) + wufc &= ~ATL1_WUFC_LNKC; + + /* reduce speed to 10/100M */ + if (wufc) { + atl1_phy_enter_power_saving(hw); + /* if resume, let driver to re- setup link */ + hw->phy_configured = false; + atl1_set_mac_addr(hw); + atl1_set_multi(netdev); + + ctrl = 0; + /* turn on magic packet wol */ + if (wufc & ATL1_WUFC_MAG) + ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN; + + /* turn on Link change WOL */ + if (wufc & ATL1_WUFC_LNKC) + ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); + iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); + + /* turn on all-multi mode if wake on multicast is enabled */ + ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_DBG; + ctrl &= ~MAC_CTRL_PROMIS_EN; + if (wufc & ATL1_WUFC_MC) + ctrl |= MAC_CTRL_MC_ALL_EN; + else + ctrl &= ~MAC_CTRL_MC_ALL_EN; + + /* turn on broadcast mode if wake on-BC is enabled */ + if (wufc & ATL1_WUFC_BC) + ctrl |= MAC_CTRL_BC_EN; + else + ctrl &= ~MAC_CTRL_BC_EN; + + /* enable RX */ + ctrl |= MAC_CTRL_RX_EN; + iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL); + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); /* 4 == D3 cold */ + } else { + iowrite32(0, hw->hw_addr + REG_WOL_CTRL); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */ + } + + pci_save_state(pdev); + pci_disable_device(pdev); + + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int atl1_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter = netdev_priv(netdev); + u32 ret_val; + + pci_set_power_state(pdev, 0); + pci_restore_state(pdev); + + ret_val = pci_enable_device(pdev); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); + atl1_reset(adapter); + + if (netif_running(netdev)) + atl1_up(adapter); + netif_device_attach(netdev); + + atl1_via_workaround(adapter); + + return 0; +} +#else +#define atl1_suspend NULL +#define atl1_resume NULL +#endif + +static struct pci_driver atl1_driver = { + .name = atl1_driver_name, + .id_table = atl1_pci_tbl, + .probe = atl1_probe, + .remove = __devexit_p(atl1_remove), + /* Power Managment Hooks */ + /* probably broken right now -- CHS */ + .suspend = atl1_suspend, + .resume = atl1_resume +}; + +/* + * atl1_exit_module - Driver Exit Cleanup Routine + * + * atl1_exit_module is called just before the driver is removed + * from memory. + */ +static void __exit atl1_exit_module(void) +{ + pci_unregister_driver(&atl1_driver); +} + +/* + * atl1_init_module - Driver Registration Routine + * + * atl1_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + */ +static int __init atl1_init_module(void) +{ + printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION); + printk(KERN_INFO "%s\n", atl1_copyright); + return pci_register_driver(&atl1_driver); +} + +module_init(atl1_init_module); +module_exit(atl1_exit_module); diff --git a/trunk/drivers/net/atl1/atl1_param.c b/trunk/drivers/net/atl1/atl1_param.c new file mode 100644 index 000000000000..c407214339f6 --- /dev/null +++ b/trunk/drivers/net/atl1/atl1_param.c @@ -0,0 +1,206 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * 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 +#include +#include +#include "atl1.h" + +/* + * This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ +#define ATL1_MAX_NIC 4 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET } + +/* + * Interrupt Moderate Timer in units of 2 us + * + * Valid Range: 10-65535 + * + * Default Value: 100 (200us) + */ +static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; +static int num_int_mod_timer = 0; +module_param_array_named(int_mod_timer, int_mod_timer, int, &num_int_mod_timer, 0); +MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer"); + +/* + * flash_vendor + * + * Valid Range: 0-2 + * + * 0 - Atmel + * 1 - SST + * 2 - ST + * + * Default Value: 0 + */ +static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; +static int num_flash_vendor = 0; +module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0); +MODULE_PARM_DESC(flash_vendor, "SPI flash vendor"); + +#define DEFAULT_INT_MOD_CNT 100 /* 200us */ +#define MAX_INT_MOD_CNT 65000 +#define MIN_INT_MOD_CNT 50 + +#define FLASH_VENDOR_DEFAULT 0 +#define FLASH_VENDOR_MIN 0 +#define FLASH_VENDOR_MAX 2 + +struct atl1_option { + enum { enable_option, range_option, list_option } type; + char *name; + char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct atl1_opt_list { + int i; + char *str; + } *p; + } l; + } arg; +}; + +static int __devinit atl1_validate_option(int *value, struct atl1_option *opt) +{ + if (*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name, + opt->name); + return 0; + case OPTION_DISABLED: + printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name, + opt->name); + return 0; + } + break; + case range_option: + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + printk(KERN_INFO "%s: %s set to %i\n", + atl1_driver_name, opt->name, *value); + return 0; + } + break; + case list_option:{ + int i; + struct atl1_opt_list *ent; + + for (i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if (*value == ent->i) { + if (ent->str[0] != '\0') + printk(KERN_INFO "%s: %s\n", + atl1_driver_name, ent->str); + return 0; + } + } + } + break; + + default: + break; + } + + printk(KERN_INFO "%s: invalid %s specified (%i) %s\n", + atl1_driver_name, opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +/* + * atl1_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line parameters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + */ +void __devinit atl1_check_options(struct atl1_adapter *adapter) +{ + int bd = adapter->bd_number; + if (bd >= ATL1_MAX_NIC) { + printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n", + atl1_driver_name, bd); + printk(KERN_NOTICE "%s: using defaults for all values\n", + atl1_driver_name); + } + { /* Interrupt Moderate Timer */ + struct atl1_option opt = { + .type = range_option, + .name = "Interrupt Moderator Timer", + .err = "using default of " + __MODULE_STRING(DEFAULT_INT_MOD_CNT), + .def = DEFAULT_INT_MOD_CNT, + .arg = {.r = + {.min = MIN_INT_MOD_CNT,.max = MAX_INT_MOD_CNT}} + }; + int val; + if (num_int_mod_timer > bd) { + val = int_mod_timer[bd]; + atl1_validate_option(&val, &opt); + adapter->imt = (u16) val; + } else + adapter->imt = (u16) (opt.def); + } + + { /* Flash Vendor */ + struct atl1_option opt = { + .type = range_option, + .name = "SPI Flash Vendor", + .err = "using default of " + __MODULE_STRING(FLASH_VENDOR_DEFAULT), + .def = DEFAULT_INT_MOD_CNT, + .arg = {.r = + {.min = FLASH_VENDOR_MIN,.max = + FLASH_VENDOR_MAX}} + }; + int val; + if (num_flash_vendor > bd) { + val = flash_vendor[bd]; + atl1_validate_option(&val, &opt); + adapter->hw.flash_vendor = (u8) val; + } else + adapter->hw.flash_vendor = (u8) (opt.def); + } +} diff --git a/trunk/drivers/net/bonding/bond_alb.c b/trunk/drivers/net/bonding/bond_alb.c index 32923162179e..217a2eedee0a 100644 --- a/trunk/drivers/net/bonding/bond_alb.c +++ b/trunk/drivers/net/bonding/bond_alb.c @@ -184,7 +184,7 @@ static int tlb_initialize(struct bonding *bond) spin_lock_init(&(bond_info->tx_hashtbl_lock)); - new_hashtbl = kmalloc(size, GFP_KERNEL); + new_hashtbl = kzalloc(size, GFP_KERNEL); if (!new_hashtbl) { printk(KERN_ERR DRV_NAME ": %s: Error: Failed to allocate TLB hash table\n", @@ -195,8 +195,6 @@ static int tlb_initialize(struct bonding *bond) bond_info->tx_hashtbl = new_hashtbl; - memset(bond_info->tx_hashtbl, 0, size); - for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); } diff --git a/trunk/drivers/net/bonding/bond_main.c b/trunk/drivers/net/bonding/bond_main.c index d3801a00d3d5..8ce8fec615ba 100644 --- a/trunk/drivers/net/bonding/bond_main.c +++ b/trunk/drivers/net/bonding/bond_main.c @@ -1343,14 +1343,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) "inaccurate.\n", bond_dev->name, slave_dev->name); } - new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL); + new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); if (!new_slave) { res = -ENOMEM; goto err_undo_flags; } - memset(new_slave, 0, sizeof(struct slave)); - /* save slave's original flags before calling * netdev_set_master and dev_open */ diff --git a/trunk/drivers/net/cxgb3/cxgb3_main.c b/trunk/drivers/net/cxgb3/cxgb3_main.c index dfa035a1ad45..c67f7d3c2f92 100644 --- a/trunk/drivers/net/cxgb3/cxgb3_main.c +++ b/trunk/drivers/net/cxgb3/cxgb3_main.c @@ -74,8 +74,6 @@ enum { #define EEPROM_MAGIC 0x38E2F10C -#define to_net_dev(class) container_of(class, struct net_device, class_dev) - #define CH_DEVICE(devid, ssid, idx) \ { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx } @@ -434,11 +432,12 @@ static int setup_sge_qsets(struct adapter *adap) return 0; } -static ssize_t attr_show(struct class_device *cd, char *buf, +static ssize_t attr_show(struct device *d, struct device_attribute *attr, + char *buf, ssize_t(*format) (struct adapter *, char *)) { ssize_t len; - struct adapter *adap = to_net_dev(cd)->priv; + struct adapter *adap = to_net_dev(d)->priv; /* Synchronize with ioctls that may shut down the device */ rtnl_lock(); @@ -447,14 +446,15 @@ static ssize_t attr_show(struct class_device *cd, char *buf, return len; } -static ssize_t attr_store(struct class_device *cd, const char *buf, size_t len, +static ssize_t attr_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t len, ssize_t(*set) (struct adapter *, unsigned int), unsigned int min_val, unsigned int max_val) { char *endp; ssize_t ret; unsigned int val; - struct adapter *adap = to_net_dev(cd)->priv; + struct adapter *adap = to_net_dev(d)->priv; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -476,9 +476,10 @@ static ssize_t format_##name(struct adapter *adap, char *buf) \ { \ return sprintf(buf, "%u\n", val_expr); \ } \ -static ssize_t show_##name(struct class_device *cd, char *buf) \ +static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ + char *buf) \ { \ - return attr_show(cd, buf, format_##name); \ + return attr_show(d, attr, buf, format_##name); \ } static ssize_t set_nfilters(struct adapter *adap, unsigned int val) @@ -493,10 +494,10 @@ static ssize_t set_nfilters(struct adapter *adap, unsigned int val) return 0; } -static ssize_t store_nfilters(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_nfilters(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) { - return attr_store(cd, buf, len, set_nfilters, 0, ~0); + return attr_store(d, attr, buf, len, set_nfilters, 0, ~0); } static ssize_t set_nservers(struct adapter *adap, unsigned int val) @@ -509,38 +510,39 @@ static ssize_t set_nservers(struct adapter *adap, unsigned int val) return 0; } -static ssize_t store_nservers(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_nservers(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) { - return attr_store(cd, buf, len, set_nservers, 0, ~0); + return attr_store(d, attr, buf, len, set_nservers, 0, ~0); } #define CXGB3_ATTR_R(name, val_expr) \ CXGB3_SHOW(name, val_expr) \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) #define CXGB3_ATTR_RW(name, val_expr, store_method) \ CXGB3_SHOW(name, val_expr) \ -static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method) +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method) CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5)); CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters); CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers); static struct attribute *cxgb3_attrs[] = { - &class_device_attr_cam_size.attr, - &class_device_attr_nfilters.attr, - &class_device_attr_nservers.attr, + &dev_attr_cam_size.attr, + &dev_attr_nfilters.attr, + &dev_attr_nservers.attr, NULL }; static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs }; -static ssize_t tm_attr_show(struct class_device *cd, char *buf, int sched) +static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr, + char *buf, int sched) { ssize_t len; unsigned int v, addr, bpt, cpt; - struct adapter *adap = to_net_dev(cd)->priv; + struct adapter *adap = to_net_dev(d)->priv; addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; rtnl_lock(); @@ -560,13 +562,13 @@ static ssize_t tm_attr_show(struct class_device *cd, char *buf, int sched) return len; } -static ssize_t tm_attr_store(struct class_device *cd, const char *buf, - size_t len, int sched) +static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t len, int sched) { char *endp; ssize_t ret; unsigned int val; - struct adapter *adap = to_net_dev(cd)->priv; + struct adapter *adap = to_net_dev(d)->priv; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -584,15 +586,17 @@ static ssize_t tm_attr_store(struct class_device *cd, const char *buf, } #define TM_ATTR(name, sched) \ -static ssize_t show_##name(struct class_device *cd, char *buf) \ +static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ + char *buf) \ { \ - return tm_attr_show(cd, buf, sched); \ + return tm_attr_show(d, attr, buf, sched); \ } \ -static ssize_t store_##name(struct class_device *cd, const char *buf, size_t len) \ +static ssize_t store_##name(struct device *d, struct device_attribute *attr, \ + const char *buf, size_t len) \ { \ - return tm_attr_store(cd, buf, len, sched); \ + return tm_attr_store(d, attr, buf, len, sched); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) TM_ATTR(sched0, 0); TM_ATTR(sched1, 1); @@ -604,14 +608,14 @@ TM_ATTR(sched6, 6); TM_ATTR(sched7, 7); static struct attribute *offload_attrs[] = { - &class_device_attr_sched0.attr, - &class_device_attr_sched1.attr, - &class_device_attr_sched2.attr, - &class_device_attr_sched3.attr, - &class_device_attr_sched4.attr, - &class_device_attr_sched5.attr, - &class_device_attr_sched6.attr, - &class_device_attr_sched7.attr, + &dev_attr_sched0.attr, + &dev_attr_sched1.attr, + &dev_attr_sched2.attr, + &dev_attr_sched3.attr, + &dev_attr_sched4.attr, + &dev_attr_sched5.attr, + &dev_attr_sched6.attr, + &dev_attr_sched7.attr, NULL }; @@ -836,7 +840,7 @@ static int offload_open(struct net_device *dev) init_smt(adapter); /* Never mind if the next step fails */ - sysfs_create_group(&tdev->lldev->class_dev.kobj, &offload_attr_group); + sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group); /* Call back all registered clients */ cxgb3_add_clients(tdev); @@ -861,7 +865,7 @@ static int offload_close(struct t3cdev *tdev) /* Call back all registered clients */ cxgb3_remove_clients(tdev); - sysfs_remove_group(&tdev->lldev->class_dev.kobj, &offload_attr_group); + sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group); tdev->lldev = NULL; cxgb3_set_dummy_ops(tdev); @@ -2420,7 +2424,7 @@ static int __devinit init_one(struct pci_dev *pdev, else if (msi > 0 && pci_enable_msi(pdev) == 0) adapter->flags |= USING_MSI; - err = sysfs_create_group(&adapter->port[0]->class_dev.kobj, + err = sysfs_create_group(&adapter->port[0]->dev.kobj, &cxgb3_attr_group); print_port_info(adapter, ai); @@ -2452,7 +2456,7 @@ static void __devexit remove_one(struct pci_dev *pdev) struct adapter *adapter = dev->priv; t3_sge_stop(adapter); - sysfs_remove_group(&adapter->port[0]->class_dev.kobj, + sysfs_remove_group(&adapter->port[0]->dev.kobj, &cxgb3_attr_group); for_each_port(adapter, i) diff --git a/trunk/drivers/net/cxgb3/cxgb3_offload.c b/trunk/drivers/net/cxgb3/cxgb3_offload.c index c3a02d613382..c6b726643185 100644 --- a/trunk/drivers/net/cxgb3/cxgb3_offload.c +++ b/trunk/drivers/net/cxgb3/cxgb3_offload.c @@ -396,7 +396,7 @@ static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs, int n) { CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n", - n, ntohl(*(u32 *)skbs[0]->data)); + n, ntohl(*(__be32 *)skbs[0]->data)); while (n--) dev_kfree_skb_any(skbs[n]); return 0; @@ -755,7 +755,7 @@ static int do_trace(struct t3cdev *dev, struct sk_buff *skb) { struct cpl_trace_pkt *p = cplhdr(skb); - skb->protocol = 0xffff; + skb->protocol = htons(0xffff); skb->dev = dev->lldev; skb_pull(skb, sizeof(*p)); skb->mac.raw = skb->data; diff --git a/trunk/drivers/net/defxx.c b/trunk/drivers/net/defxx.c index dc3ab3b5c8cb..07d2731c1aa8 100644 --- a/trunk/drivers/net/defxx.c +++ b/trunk/drivers/net/defxx.c @@ -10,10 +10,12 @@ * * Abstract: * A Linux device driver supporting the Digital Equipment Corporation - * FDDI EISA and PCI controller families. Supported adapters include: + * FDDI TURBOchannel, EISA and PCI controller families. Supported + * adapters include: * - * DEC FDDIcontroller/EISA (DEFEA) - * DEC FDDIcontroller/PCI (DEFPA) + * DEC FDDIcontroller/TURBOchannel (DEFTA) + * DEC FDDIcontroller/EISA (DEFEA) + * DEC FDDIcontroller/PCI (DEFPA) * * The original author: * LVS Lawrence V. Stefani @@ -193,24 +195,27 @@ * 14 Aug 2004 macro Fix device names reported. * 14 Jun 2005 macro Use irqreturn_t. * 23 Oct 2006 macro Big-endian host support. + * 14 Dec 2006 macro TURBOchannel support. */ /* Include files */ - -#include -#include -#include -#include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include #include +#include +#include +#include +#include #include -#include +#include #include -#include +#include +#include +#include #include #include @@ -219,8 +224,8 @@ /* Version information string should be updated prior to each new release! */ #define DRV_NAME "defxx" -#define DRV_VERSION "v1.09" -#define DRV_RELDATE "2006/10/23" +#define DRV_VERSION "v1.10" +#define DRV_RELDATE "2006/12/14" static char version[] __devinitdata = DRV_NAME ": " DRV_VERSION " " DRV_RELDATE @@ -235,12 +240,41 @@ static char version[] __devinitdata = */ #define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128) +#define __unused __attribute__ ((unused)) + +#ifdef CONFIG_PCI +#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type) +#else +#define DFX_BUS_PCI(dev) 0 +#endif + +#ifdef CONFIG_EISA +#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type) +#else +#define DFX_BUS_EISA(dev) 0 +#endif + +#ifdef CONFIG_TC +#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type) +#else +#define DFX_BUS_TC(dev) 0 +#endif + +#ifdef CONFIG_DEFXX_MMIO +#define DFX_MMIO 1 +#else +#define DFX_MMIO 0 +#endif + /* Define module-wide (static) routines */ static void dfx_bus_init(struct net_device *dev); +static void dfx_bus_uninit(struct net_device *dev); static void dfx_bus_config_check(DFX_board_t *bp); -static int dfx_driver_init(struct net_device *dev, const char *print_name); +static int dfx_driver_init(struct net_device *dev, + const char *print_name, + resource_size_t bar_start); static int dfx_adap_init(DFX_board_t *bp, int get_buffers); static int dfx_open(struct net_device *dev); @@ -273,13 +307,13 @@ static void dfx_xmt_flush(DFX_board_t *bp); /* Define module-wide (static) variables */ -static struct net_device *root_dfx_eisa_dev; +static struct pci_driver dfx_pci_driver; +static struct eisa_driver dfx_eisa_driver; +static struct tc_driver dfx_tc_driver; /* * ======================= - * = dfx_port_write_byte = - * = dfx_port_read_byte = * = dfx_port_write_long = * = dfx_port_read_long = * ======================= @@ -291,12 +325,11 @@ static struct net_device *root_dfx_eisa_dev; * None * * Arguments: - * bp - pointer to board information - * offset - register offset from base I/O address - * data - for dfx_port_write_byte and dfx_port_write_long, this - * is a value to write. - * for dfx_port_read_byte and dfx_port_read_byte, this - * is a pointer to store the read value. + * bp - pointer to board information + * offset - register offset from base I/O address + * data - for dfx_port_write_long, this is a value to write; + * for dfx_port_read_long, this is a pointer to store + * the read value * * Functional Description: * These routines perform the correct operation to read or write @@ -310,7 +343,7 @@ static struct net_device *root_dfx_eisa_dev; * registers using the register offsets defined in DEFXX.H. * * PCI port block base addresses are assigned by the PCI BIOS or system - * firmware. There is one 128 byte port block which can be accessed. It + * firmware. There is one 128 byte port block which can be accessed. It * allows for I/O mapping of both PDQ and PFI registers using the register * offsets defined in DEFXX.H. * @@ -318,7 +351,7 @@ static struct net_device *root_dfx_eisa_dev; * None * * Assumptions: - * bp->base_addr is a valid base I/O address for this adapter. + * bp->base is a valid base I/O address for this adapter. * offset is a valid register offset for this adapter. * * Side Effects: @@ -329,69 +362,135 @@ static struct net_device *root_dfx_eisa_dev; * advantage of strict data type checking. */ -static inline void dfx_port_write_byte( - DFX_board_t *bp, - int offset, - u8 data - ) +static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data) +{ + writel(data, bp->base.mem + offset); + mb(); +} - { - u16 port = bp->base_addr + offset; +static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data) +{ + outl(data, bp->base.port + offset); +} - outb(data, port); - } +static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data) +{ + struct device __unused *bdev = bp->bus_dev; + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; -static inline void dfx_port_read_byte( - DFX_board_t *bp, - int offset, - u8 *data - ) + if (dfx_use_mmio) + dfx_writel(bp, offset, data); + else + dfx_outl(bp, offset, data); +} - { - u16 port = bp->base_addr + offset; - *data = inb(port); - } +static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data) +{ + mb(); + *data = readl(bp->base.mem + offset); +} -static inline void dfx_port_write_long( - DFX_board_t *bp, - int offset, - u32 data - ) +static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data) +{ + *data = inl(bp->base.port + offset); +} - { - u16 port = bp->base_addr + offset; +static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) +{ + struct device __unused *bdev = bp->bus_dev; + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - outl(data, port); - } + if (dfx_use_mmio) + dfx_readl(bp, offset, data); + else + dfx_inl(bp, offset, data); +} -static inline void dfx_port_read_long( - DFX_board_t *bp, - int offset, - u32 *data - ) - { - u16 port = bp->base_addr + offset; +/* + * ================ + * = dfx_get_bars = + * ================ + * + * Overview: + * Retrieves the address range used to access control and status + * registers. + * + * Returns: + * None + * + * Arguments: + * bdev - pointer to device information + * bar_start - pointer to store the start address + * bar_len - pointer to store the length of the area + * + * Assumptions: + * I am sure there are some. + * + * Side Effects: + * None + */ +static void dfx_get_bars(struct device *bdev, + resource_size_t *bar_start, resource_size_t *bar_len) +{ + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - *data = inl(port); - } + if (dfx_bus_pci) { + int num = dfx_use_mmio ? 0 : 1; + *bar_start = pci_resource_start(to_pci_dev(bdev), num); + *bar_len = pci_resource_len(to_pci_dev(bdev), num); + } + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + resource_size_t bar; + + if (dfx_use_mmio) { + bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0); + bar <<= 16; + *bar_start = bar; + bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0); + bar <<= 16; + *bar_len = (bar | PI_MEM_ADD_MASK_M) + 1; + } else { + *bar_start = base_addr; + *bar_len = PI_ESIC_K_CSR_IO_LEN; + } + } + if (dfx_bus_tc) { + *bar_start = to_tc_dev(bdev)->resource.start + + PI_TC_K_CSR_OFFSET; + *bar_len = PI_TC_K_CSR_LEN; + } +} /* - * ============= - * = dfx_init_one_pci_or_eisa = - * ============= + * ================ + * = dfx_register = + * ================ * * Overview: - * Initializes a supported FDDI EISA or PCI controller + * Initializes a supported FDDI controller * * Returns: * Condition code * * Arguments: - * pdev - pointer to pci device information (NULL for EISA) - * ioaddr - pointer to port (NULL for PCI) + * bdev - pointer to device information * * Functional Description: * @@ -407,56 +506,74 @@ static inline void dfx_port_read_long( * initialized and the board resources are read and stored in * the device structure. */ -static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr) +static int __devinit dfx_register(struct device *bdev) { static int version_disp; - char *print_name = DRV_NAME; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + char *print_name = bdev->bus_id; struct net_device *dev; DFX_board_t *bp; /* board pointer */ + resource_size_t bar_start = 0; /* pointer to port */ + resource_size_t bar_len = 0; /* resource length */ int alloc_size; /* total buffer size used */ - int err; + struct resource *region; + int err = 0; if (!version_disp) { /* display version info if adapter is found */ version_disp = 1; /* set display flag to TRUE so that */ printk(version); /* we only display this string ONCE */ } - if (pdev != NULL) - print_name = pci_name(pdev); - dev = alloc_fddidev(sizeof(*bp)); if (!dev) { - printk(KERN_ERR "%s: unable to allocate fddidev, aborting\n", + printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n", print_name); return -ENOMEM; } /* Enable PCI device. */ - if (pdev != NULL) { - err = pci_enable_device (pdev); - if (err) goto err_out; - ioaddr = pci_resource_start (pdev, 1); + if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) { + printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n", + print_name); + goto err_out; } SET_MODULE_OWNER(dev); - if (pdev != NULL) - SET_NETDEV_DEV(dev, &pdev->dev); + SET_NETDEV_DEV(dev, bdev); + + bp = netdev_priv(dev); + bp->bus_dev = bdev; + dev_set_drvdata(bdev, dev); - bp = dev->priv; + dfx_get_bars(bdev, &bar_start, &bar_len); - if (!request_region(ioaddr, - pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, - print_name)) { + if (dfx_use_mmio) + region = request_mem_region(bar_start, bar_len, print_name); + else + region = request_region(bar_start, bar_len, print_name); + if (!region) { printk(KERN_ERR "%s: Cannot reserve I/O resource " - "0x%x @ 0x%lx, aborting\n", print_name, - pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, ioaddr); + "0x%lx @ 0x%lx, aborting\n", + print_name, (long)bar_len, (long)bar_start); err = -EBUSY; - goto err_out; + goto err_out_disable; } - /* Initialize new device structure */ + /* Set up I/O base address. */ + if (dfx_use_mmio) { + bp->base.mem = ioremap_nocache(bar_start, bar_len); + if (!bp->base.mem) { + printk(KERN_ERR "%s: Cannot map MMIO\n", print_name); + goto err_out_region; + } + } else { + bp->base.port = bar_start; + dev->base_addr = bar_start; + } - dev->base_addr = ioaddr; /* save port (I/O) base address */ + /* Initialize new device structure */ dev->get_stats = dfx_ctl_get_stats; dev->open = dfx_open; @@ -465,22 +582,12 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr) dev->set_multicast_list = dfx_ctl_set_multicast_list; dev->set_mac_address = dfx_ctl_set_mac_address; - if (pdev == NULL) { - /* EISA board */ - bp->bus_type = DFX_BUS_TYPE_EISA; - bp->next = root_dfx_eisa_dev; - root_dfx_eisa_dev = dev; - } else { - /* PCI board */ - bp->bus_type = DFX_BUS_TYPE_PCI; - bp->pci_dev = pdev; - pci_set_drvdata (pdev, dev); - pci_set_master (pdev); - } + if (dfx_bus_pci) + pci_set_master(to_pci_dev(bdev)); - if (dfx_driver_init(dev, print_name) != DFX_K_SUCCESS) { + if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) { err = -ENODEV; - goto err_out_region; + goto err_out_unmap; } err = register_netdev(dev); @@ -499,44 +606,28 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr) sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); if (bp->kmalloced) - pci_free_consistent(pdev, alloc_size, - bp->kmalloced, bp->kmalloced_dma); + dma_free_coherent(bdev, alloc_size, + bp->kmalloced, bp->kmalloced_dma); + +err_out_unmap: + if (dfx_use_mmio) + iounmap(bp->base.mem); + err_out_region: - release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN); + if (dfx_use_mmio) + release_mem_region(bar_start, bar_len); + else + release_region(bar_start, bar_len); + +err_out_disable: + if (dfx_bus_pci) + pci_disable_device(to_pci_dev(bdev)); + err_out: free_netdev(dev); return err; } -static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - return dfx_init_one_pci_or_eisa(pdev, 0); -} - -static int __init dfx_eisa_init(void) -{ - int rc = -ENODEV; - int i; /* used in for loops */ - u16 port; /* temporary I/O (port) address */ - u32 slot_id; /* EISA hardware (slot) ID read from adapter */ - - DBG_printk("In dfx_eisa_init...\n"); - - /* Scan for FDDI EISA controllers */ - - for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */ - { - port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */ - slot_id = inl(port); /* read EISA HW (slot) ID */ - if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID) - { - port = (i << 12); /* recalc base addr */ - - if (dfx_init_one_pci_or_eisa(NULL, port) == 0) rc = 0; - } - } - return rc; -} /* * ================ @@ -544,7 +635,7 @@ static int __init dfx_eisa_init(void) * ================ * * Overview: - * Initializes EISA and PCI controller bus-specific logic. + * Initializes the bus-specific controller logic. * * Returns: * None @@ -560,7 +651,7 @@ static int __init dfx_eisa_init(void) * None * * Assumptions: - * dev->base_addr has already been set with the proper + * bp->base has already been set with the proper * base I/O address for this device. * * Side Effects: @@ -571,87 +662,103 @@ static int __init dfx_eisa_init(void) static void __devinit dfx_bus_init(struct net_device *dev) { - DFX_board_t *bp = dev->priv; - u8 val; /* used for I/O read/writes */ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + u8 val; DBG_printk("In dfx_bus_init...\n"); - /* - * Initialize base I/O address field in bp structure - * - * Note: bp->base_addr is the same as dev->base_addr. - * It's useful because often we'll need to read - * or write registers where we already have the - * bp pointer instead of the dev pointer. Having - * the base address in the bp structure will - * save a pointer dereference. - * - * IMPORTANT!! This field must be defined before - * any of the dfx_port_* inline functions are - * called. - */ - - bp->base_addr = dev->base_addr; - - /* And a pointer back to the net_device struct */ + /* Initialize a pointer back to the net_device struct */ bp->dev = dev; /* Initialize adapter based on bus type */ - if (bp->bus_type == DFX_BUS_TYPE_EISA) - { - /* Get the interrupt level from the ESIC chip */ - - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); - switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ) - { - case PI_CONFIG_STAT_0_IRQ_K_9: - dev->irq = 9; - break; - - case PI_CONFIG_STAT_0_IRQ_K_10: - dev->irq = 10; - break; + if (dfx_bus_tc) + dev->irq = to_tc_dev(bdev)->interrupt; + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; - case PI_CONFIG_STAT_0_IRQ_K_11: - dev->irq = 11; - break; + /* Get the interrupt level from the ESIC chip. */ + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val &= PI_CONFIG_STAT_0_M_IRQ; + val >>= PI_CONFIG_STAT_0_V_IRQ; - case PI_CONFIG_STAT_0_IRQ_K_15: - dev->irq = 15; - break; - } - - /* Enable access to I/O on the board by writing 0x03 to Function Control Register */ + switch (val) { + case PI_CONFIG_STAT_0_IRQ_K_9: + dev->irq = 9; + break; - dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB); + case PI_CONFIG_STAT_0_IRQ_K_10: + dev->irq = 10; + break; - /* Set the I/O decode range of the board */ + case PI_CONFIG_STAT_0_IRQ_K_11: + dev->irq = 11; + break; - val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT); - dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val); - dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val); + case PI_CONFIG_STAT_0_IRQ_K_15: + dev->irq = 15; + break; + } - /* Enable access to rest of module (including PDQ and packet memory) */ + /* + * Enable memory decoding (MEMCS0) and/or port decoding + * (IOCS1/IOCS0) as appropriate in Function Control + * Register. One of the port chip selects seems to be + * used for the Burst Holdoff register, but this bit of + * documentation is missing and as yet it has not been + * determined which of the two. This is also the reason + * the size of the decoded port range is twice as large + * as one required by the PDQ. + */ - dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB); + /* Set the decode range of the board. */ + val = ((bp->base.port >> 12) << PI_IO_CMP_V_SLOT); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_1, val); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_0, 0); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_1, val); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_0, 0); + val = PI_ESIC_K_CSR_IO_LEN - 1; + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_1, (val >> 8) & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_0, val & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_1, (val >> 8) & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_0, val & 0xff); + + /* Enable the decoders. */ + val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0; + if (dfx_use_mmio) + val |= PI_FUNCTION_CNTRL_M_MEMCS0; + outb(base_addr + PI_ESIC_K_FUNCTION_CNTRL, val); /* - * Map PDQ registers into I/O space. This is done by clearing a bit - * in Burst Holdoff register. + * Enable access to the rest of the module + * (including PDQ and packet memory). */ + val = PI_SLOT_CNTRL_M_ENB; + outb(base_addr + PI_ESIC_K_SLOT_CNTRL, val); - dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val); - dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP)); + /* + * Map PDQ registers into memory or port space. This is + * done with a bit in the Burst Holdoff register. + */ + val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF); + if (dfx_use_mmio) + val |= PI_BURST_HOLDOFF_V_MEM_MAP; + else + val &= ~PI_BURST_HOLDOFF_V_MEM_MAP; + outb(base_addr + PI_DEFEA_K_BURST_HOLDOFF, val); /* Enable interrupts at EISA bus interface chip (ESIC) */ - - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); - dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB)); - } - else - { - struct pci_dev *pdev = bp->pci_dev; + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val |= PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); + } + if (dfx_bus_pci) { + struct pci_dev *pdev = to_pci_dev(bdev); /* Get the interrupt level from the PCI Configuration Table */ @@ -660,17 +767,70 @@ static void __devinit dfx_bus_init(struct net_device *dev) /* Check Latency Timer and set if less than minimal */ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val); - if (val < PFI_K_LAT_TIMER_MIN) /* if less than min, override with default */ - { + if (val < PFI_K_LAT_TIMER_MIN) { val = PFI_K_LAT_TIMER_DEF; pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val); - } + } /* Enable interrupts at PCI bus interface chip (PFI) */ + val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB; + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val); + } +} - dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB)); - } +/* + * ================== + * = dfx_bus_uninit = + * ================== + * + * Overview: + * Uninitializes the bus-specific controller logic. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Perform bus-specific logic uninitialization. + * + * Return Codes: + * None + * + * Assumptions: + * bp->base has already been set with the proper + * base I/O address for this device. + * + * Side Effects: + * Interrupts are disabled at the adapter bus-specific logic. + */ + +static void __devinit dfx_bus_uninit(struct net_device *dev) +{ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + u8 val; + + DBG_printk("In dfx_bus_uninit...\n"); + + /* Uninitialize adapter based on bus type */ + + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + + /* Disable interrupts at EISA bus interface chip (ESIC) */ + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val &= ~PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); + } + if (dfx_bus_pci) { + /* Disable interrupts at PCI bus interface chip (PFI) */ + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0); } +} /* @@ -705,18 +865,16 @@ static void __devinit dfx_bus_init(struct net_device *dev) static void __devinit dfx_bus_config_check(DFX_board_t *bp) { + struct device __unused *bdev = bp->bus_dev; + int dfx_bus_eisa = DFX_BUS_EISA(bdev); int status; /* return code from adapter port control call */ - u32 slot_id; /* EISA-bus hardware id (DEC3001, DEC3002,...) */ u32 host_data; /* LW data returned from port control call */ DBG_printk("In dfx_bus_config_check...\n"); /* Configuration check only valid for EISA adapter */ - if (bp->bus_type == DFX_BUS_TYPE_EISA) - { - dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id); - + if (dfx_bus_eisa) { /* * First check if revision 2 EISA controller. Rev. 1 cards used * PDQ revision B, so no workaround needed in this case. Rev. 3 @@ -724,14 +882,11 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp) * case, either. Only Rev. 2 cards used either Rev. D or E * chips, so we must verify the chip revision on Rev. 2 cards. */ - - if (slot_id == DEFEA_PROD_ID_2) - { + if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) { /* - * Revision 2 FDDI EISA controller found, so let's check PDQ - * revision of adapter. + * Revision 2 FDDI EISA controller found, + * so let's check PDQ revision of adapter. */ - status = dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_SUB_CMD, PI_SUB_CMD_K_PDQ_REV_GET, @@ -805,13 +960,20 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp) */ static int __devinit dfx_driver_init(struct net_device *dev, - const char *print_name) + const char *print_name, + resource_size_t bar_start) { - DFX_board_t *bp = dev->priv; - int alloc_size; /* total buffer size needed */ - char *top_v, *curr_v; /* virtual addrs into memory block */ - dma_addr_t top_p, curr_p; /* physical addrs into memory block */ - u32 data; /* host data register value */ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + int alloc_size; /* total buffer size needed */ + char *top_v, *curr_v; /* virtual addrs into memory block */ + dma_addr_t top_p, curr_p; /* physical addrs into memory block */ + u32 data, le32; /* host data register value */ + char *board_name = NULL; DBG_printk("In dfx_driver_init...\n"); @@ -860,8 +1022,8 @@ static int __devinit dfx_driver_init(struct net_device *dev, print_name); return(DFX_K_FAILURE); } - data = cpu_to_le32(data); - memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32)); + le32 = cpu_to_le32(data); + memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32)); if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0, &data) != DFX_K_SUCCESS) { @@ -869,8 +1031,8 @@ static int __devinit dfx_driver_init(struct net_device *dev, print_name); return(DFX_K_FAILURE); } - data = cpu_to_le32(data); - memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16)); + le32 = cpu_to_le32(data); + memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16)); /* * Set current address to factory address @@ -880,20 +1042,18 @@ static int __devinit dfx_driver_init(struct net_device *dev, */ memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); - if (bp->bus_type == DFX_BUS_TYPE_EISA) - printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, " - "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", - print_name, dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); - else - printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, " - "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", - print_name, dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + if (dfx_bus_tc) + board_name = "DEFTA"; + if (dfx_bus_eisa) + board_name = "DEFEA"; + if (dfx_bus_pci) + board_name = "DEFPA"; + pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, " + "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", + print_name, board_name, dfx_use_mmio ? "" : "I/O ", + (long long)bar_start, dev->irq, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* * Get memory for descriptor block, consumer block, and other buffers @@ -908,8 +1068,9 @@ static int __devinit dfx_driver_init(struct net_device *dev, #endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); - bp->kmalloced = top_v = pci_alloc_consistent(bp->pci_dev, alloc_size, - &bp->kmalloced_dma); + bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size, + &bp->kmalloced_dma, + GFP_ATOMIC); if (top_v == NULL) { printk("%s: Could not allocate memory for host buffers " "and structures!\n", print_name); @@ -1219,14 +1380,15 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers) static int dfx_open(struct net_device *dev) { + DFX_board_t *bp = netdev_priv(dev); int ret; - DFX_board_t *bp = dev->priv; DBG_printk("In dfx_open...\n"); /* Register IRQ - support shared interrupts by passing device ptr */ - ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, dev); + ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, + dev); if (ret) { printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); return ret; @@ -1309,7 +1471,7 @@ static int dfx_open(struct net_device *dev) static int dfx_close(struct net_device *dev) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); DBG_printk("In dfx_close...\n"); @@ -1645,7 +1807,7 @@ static void dfx_int_type_0_process(DFX_board_t *bp) static void dfx_int_common(struct net_device *dev) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); PI_UINT32 port_status; /* Port Status register */ /* Process xmt interrupts - frequent case, so always call this routine */ @@ -1715,18 +1877,16 @@ static void dfx_int_common(struct net_device *dev) static irqreturn_t dfx_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; - DFX_board_t *bp; /* private board structure pointer */ - - /* Get board pointer only if device structure is valid */ - - bp = dev->priv; - - /* See if we're already servicing an interrupt */ + struct net_device *dev = dev_id; + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); /* Service adapter interrupts */ - if (bp->bus_type == DFX_BUS_TYPE_PCI) { + if (dfx_bus_pci) { u32 status; dfx_port_read_long(bp, PFI_K_REG_STATUS, &status); @@ -1750,10 +1910,12 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id) PFI_MODE_M_DMA_ENB)); spin_unlock(&bp->lock); - } else { + } + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; u8 status; - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status); + status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); if (!(status & PI_CONFIG_STAT_0_M_PEND)) return IRQ_NONE; @@ -1761,15 +1923,35 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id) /* Disable interrupts at the ESIC */ status &= ~PI_CONFIG_STAT_0_M_INT_ENB; - dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status); + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); /* Call interrupt service routine for this adapter */ dfx_int_common(dev); /* Reenable interrupts at the ESIC */ - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status); + status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); status |= PI_CONFIG_STAT_0_M_INT_ENB; - dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status); + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); + + spin_unlock(&bp->lock); + } + if (dfx_bus_tc) { + u32 status; + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status); + if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING | + PI_PSTATUS_M_XMT_DATA_PENDING | + PI_PSTATUS_M_SMT_HOST_PENDING | + PI_PSTATUS_M_UNSOL_PENDING | + PI_PSTATUS_M_CMD_RSP_PENDING | + PI_PSTATUS_M_CMD_REQ_PENDING | + PI_PSTATUS_M_TYPE_0_PENDING))) + return IRQ_NONE; + + spin_lock(&bp->lock); + + /* Call interrupt service routine for this adapter */ + dfx_int_common(dev); spin_unlock(&bp->lock); } @@ -1823,7 +2005,7 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id) static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); /* Fill the bp->stats structure with driver-maintained counters */ @@ -2009,8 +2191,8 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) */ static void dfx_ctl_set_multicast_list(struct net_device *dev) - { - DFX_board_t *bp = dev->priv; +{ + DFX_board_t *bp = netdev_priv(dev); int i; /* used as index in for loop */ struct dev_mc_list *dmi; /* ptr to multicast addr entry */ @@ -2124,8 +2306,8 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev) static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr) { - DFX_board_t *bp = dev->priv; struct sockaddr *p_sockaddr = (struct sockaddr *)addr; + DFX_board_t *bp = netdev_priv(dev); /* Copy unicast address to driver-maintained structs and update count */ @@ -2764,9 +2946,9 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) my_skb_align(newskb, 128); bp->descr_block_virt->rcv_data[i + j].long_1 = - (u32)pci_map_single(bp->pci_dev, newskb->data, + (u32)dma_map_single(bp->bus_dev, newskb->data, NEW_SKB_SIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); /* * p_rcv_buff_va is only used inside the * kernel so we put the skb pointer here. @@ -2880,17 +3062,17 @@ static void dfx_rcv_queue_process( my_skb_align(newskb, 128); skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; - pci_unmap_single(bp->pci_dev, + dma_unmap_single(bp->bus_dev, bp->descr_block_virt->rcv_data[entry].long_1, NEW_SKB_SIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); skb_reserve(skb, RCV_BUFF_K_PADDING); bp->p_rcv_buff_va[entry] = (char *)newskb; bp->descr_block_virt->rcv_data[entry].long_1 = - (u32)pci_map_single(bp->pci_dev, + (u32)dma_map_single(bp->bus_dev, newskb->data, NEW_SKB_SIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); } else skb = NULL; } else @@ -3010,7 +3192,7 @@ static int dfx_xmt_queue_pkt( ) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); u8 prod; /* local transmit producer index */ PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ @@ -3116,8 +3298,8 @@ static int dfx_xmt_queue_pkt( */ p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); - p_xmt_descr->long_1 = (u32)pci_map_single(bp->pci_dev, skb->data, - skb->len, PCI_DMA_TODEVICE); + p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data, + skb->len, DMA_TO_DEVICE); /* * Verify that descriptor is actually available @@ -3220,10 +3402,10 @@ static int dfx_xmt_done(DFX_board_t *bp) /* Return skb to operating system */ comp = bp->rcv_xmt_reg.index.xmt_comp; - pci_unmap_single(bp->pci_dev, + dma_unmap_single(bp->bus_dev, bp->descr_block_virt->xmt_data[comp].long_1, p_xmt_drv_descr->p_skb->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); dev_kfree_skb_irq(p_xmt_drv_descr->p_skb); /* @@ -3344,10 +3526,10 @@ static void dfx_xmt_flush( DFX_board_t *bp ) /* Return skb to operating system */ comp = bp->rcv_xmt_reg.index.xmt_comp; - pci_unmap_single(bp->pci_dev, + dma_unmap_single(bp->bus_dev, bp->descr_block_virt->xmt_data[comp].long_1, p_xmt_drv_descr->p_skb->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); dev_kfree_skb(p_xmt_drv_descr->p_skb); /* Increment transmit error counter */ @@ -3375,13 +3557,44 @@ static void dfx_xmt_flush( DFX_board_t *bp ) bp->cons_block_virt->xmt_rcv_data = prod_cons; } -static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev) +/* + * ================== + * = dfx_unregister = + * ================== + * + * Overview: + * Shuts down an FDDI controller + * + * Returns: + * Condition code + * + * Arguments: + * bdev - pointer to device information + * + * Functional Description: + * + * Return Codes: + * None + * + * Assumptions: + * It compiles so it should work :-( (PCI cards do :-) + * + * Side Effects: + * Device structures for FDDI adapters (fddi0, fddi1, etc) are + * freed. + */ +static void __devexit dfx_unregister(struct device *bdev) { - DFX_board_t *bp = dev->priv; + struct net_device *dev = dev_get_drvdata(bdev); + DFX_board_t *bp = netdev_priv(dev); + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + resource_size_t bar_start = 0; /* pointer to port */ + resource_size_t bar_len = 0; /* resource length */ int alloc_size; /* total buffer size used */ unregister_netdev(dev); - release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN ); alloc_size = sizeof(PI_DESCR_BLOCK) + PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + @@ -3391,78 +3604,141 @@ static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct ne sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); if (bp->kmalloced) - pci_free_consistent(pdev, alloc_size, bp->kmalloced, - bp->kmalloced_dma); + dma_free_coherent(bdev, alloc_size, + bp->kmalloced, bp->kmalloced_dma); + + dfx_bus_uninit(dev); + + dfx_get_bars(bdev, &bar_start, &bar_len); + if (dfx_use_mmio) { + iounmap(bp->base.mem); + release_mem_region(bar_start, bar_len); + } else + release_region(bar_start, bar_len); + + if (dfx_bus_pci) + pci_disable_device(to_pci_dev(bdev)); + free_netdev(dev); } -static void __devexit dfx_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - dfx_remove_one_pci_or_eisa(pdev, dev); - pci_set_drvdata(pdev, NULL); -} +static int __devinit __unused dfx_dev_register(struct device *); +static int __devexit __unused dfx_dev_unregister(struct device *); -static struct pci_device_id dfx_pci_tbl[] = { - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } +#ifdef CONFIG_PCI +static int __devinit dfx_pci_register(struct pci_dev *, + const struct pci_device_id *); +static void __devexit dfx_pci_unregister(struct pci_dev *); + +static struct pci_device_id dfx_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) }, + { } }; -MODULE_DEVICE_TABLE(pci, dfx_pci_tbl); +MODULE_DEVICE_TABLE(pci, dfx_pci_table); -static struct pci_driver dfx_driver = { +static struct pci_driver dfx_pci_driver = { .name = "defxx", - .probe = dfx_init_one, - .remove = __devexit_p(dfx_remove_one), - .id_table = dfx_pci_tbl, + .id_table = dfx_pci_table, + .probe = dfx_pci_register, + .remove = __devexit_p(dfx_pci_unregister), }; -static int dfx_have_pci; -static int dfx_have_eisa; - +static __devinit int dfx_pci_register(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + return dfx_register(&pdev->dev); +} -static void __exit dfx_eisa_cleanup(void) +static void __devexit dfx_pci_unregister(struct pci_dev *pdev) { - struct net_device *dev = root_dfx_eisa_dev; + dfx_unregister(&pdev->dev); +} +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_EISA +static struct eisa_device_id dfx_eisa_table[] = { + { "DEC3001", DEFEA_PROD_ID_1 }, + { "DEC3002", DEFEA_PROD_ID_2 }, + { "DEC3003", DEFEA_PROD_ID_3 }, + { "DEC3004", DEFEA_PROD_ID_4 }, + { } +}; +MODULE_DEVICE_TABLE(eisa, dfx_eisa_table); + +static struct eisa_driver dfx_eisa_driver = { + .id_table = dfx_eisa_table, + .driver = { + .name = "defxx", + .bus = &eisa_bus_type, + .probe = dfx_dev_register, + .remove = __devexit_p(dfx_dev_unregister), + }, +}; +#endif /* CONFIG_EISA */ + +#ifdef CONFIG_TC +static struct tc_device_id const dfx_tc_table[] = { + { "DEC ", "PMAF-FA " }, + { "DEC ", "PMAF-FD " }, + { "DEC ", "PMAF-FS " }, + { "DEC ", "PMAF-FU " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dfx_tc_table); + +static struct tc_driver dfx_tc_driver = { + .id_table = dfx_tc_table, + .driver = { + .name = "defxx", + .bus = &tc_bus_type, + .probe = dfx_dev_register, + .remove = __devexit_p(dfx_dev_unregister), + }, +}; +#endif /* CONFIG_TC */ - while (dev) - { - struct net_device *tmp; - DFX_board_t *bp; +static int __devinit __unused dfx_dev_register(struct device *dev) +{ + int status; - bp = (DFX_board_t*)dev->priv; - tmp = bp->next; - dfx_remove_one_pci_or_eisa(NULL, dev); - dev = tmp; - } + status = dfx_register(dev); + if (!status) + get_device(dev); + return status; } -static int __init dfx_init(void) +static int __devexit __unused dfx_dev_unregister(struct device *dev) { - int rc_pci, rc_eisa; - - rc_pci = pci_register_driver(&dfx_driver); - if (rc_pci >= 0) dfx_have_pci = 1; + put_device(dev); + dfx_unregister(dev); + return 0; +} - rc_eisa = dfx_eisa_init(); - if (rc_eisa >= 0) dfx_have_eisa = 1; - return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci); +static int __devinit dfx_init(void) +{ + int status; + + status = pci_register_driver(&dfx_pci_driver); + if (!status) + status = eisa_driver_register(&dfx_eisa_driver); + if (!status) + status = tc_register_driver(&dfx_tc_driver); + return status; } -static void __exit dfx_cleanup(void) +static void __devexit dfx_cleanup(void) { - if (dfx_have_pci) - pci_unregister_driver(&dfx_driver); - if (dfx_have_eisa) - dfx_eisa_cleanup(); - + tc_unregister_driver(&dfx_tc_driver); + eisa_driver_unregister(&dfx_eisa_driver); + pci_unregister_driver(&dfx_pci_driver); } module_init(dfx_init); module_exit(dfx_cleanup); MODULE_AUTHOR("Lawrence V. Stefani"); -MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver " +MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver " DRV_VERSION " " DRV_RELDATE); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/defxx.h b/trunk/drivers/net/defxx.h index 2ce8f97253eb..19a6f64df198 100644 --- a/trunk/drivers/net/defxx.h +++ b/trunk/drivers/net/defxx.h @@ -26,6 +26,7 @@ * 12-Sep-96 LVS Removed packet request header pointers. * 04 Aug 2003 macro Converted to the DMA API. * 23 Oct 2006 macro Big-endian host support. + * 14 Dec 2006 macro TURBOchannel support. */ #ifndef _DEFXX_H_ @@ -1471,9 +1472,17 @@ typedef union #endif /* __BIG_ENDIAN */ +/* Define TC PDQ CSR offset and length */ + +#define PI_TC_K_CSR_OFFSET 0x100000 +#define PI_TC_K_CSR_LEN 0x40 /* 64 bytes */ + /* Define EISA controller register offsets */ -#define PI_ESIC_K_BURST_HOLDOFF 0x040 +#define PI_ESIC_K_CSR_IO_LEN 0x80 /* 128 bytes */ + +#define PI_DEFEA_K_BURST_HOLDOFF 0x040 + #define PI_ESIC_K_SLOT_ID 0xC80 #define PI_ESIC_K_SLOT_CNTRL 0xC84 #define PI_ESIC_K_MEM_ADD_CMP_0 0xC85 @@ -1488,14 +1497,14 @@ typedef union #define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E #define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F #define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90 -#define PI_ESIC_K_IO_CMP_0_0 0xC91 -#define PI_ESIC_K_IO_CMP_0_1 0xC92 -#define PI_ESIC_K_IO_CMP_1_0 0xC93 -#define PI_ESIC_K_IO_CMP_1_1 0xC94 -#define PI_ESIC_K_IO_CMP_2_0 0xC95 -#define PI_ESIC_K_IO_CMP_2_1 0xC96 -#define PI_ESIC_K_IO_CMP_3_0 0xC97 -#define PI_ESIC_K_IO_CMP_3_1 0xC98 +#define PI_ESIC_K_IO_ADD_CMP_0_0 0xC91 +#define PI_ESIC_K_IO_ADD_CMP_0_1 0xC92 +#define PI_ESIC_K_IO_ADD_CMP_1_0 0xC93 +#define PI_ESIC_K_IO_ADD_CMP_1_1 0xC94 +#define PI_ESIC_K_IO_ADD_CMP_2_0 0xC95 +#define PI_ESIC_K_IO_ADD_CMP_2_1 0xC96 +#define PI_ESIC_K_IO_ADD_CMP_3_0 0xC97 +#define PI_ESIC_K_IO_ADD_CMP_3_1 0xC98 #define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99 #define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A #define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B @@ -1518,11 +1527,16 @@ typedef union #define PI_ESIC_K_INPUT_PORT 0xCAC #define PI_ESIC_K_OUTPUT_PORT 0xCAD #define PI_ESIC_K_FUNCTION_CNTRL 0xCAE -#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */ -/* Define the value all drivers must write to the function control register. */ +/* Define the bits in the function control register. */ -#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB 0x03 +#define PI_FUNCTION_CNTRL_M_IOCS0 0x01 +#define PI_FUNCTION_CNTRL_M_IOCS1 0x02 +#define PI_FUNCTION_CNTRL_M_IOCS2 0x04 +#define PI_FUNCTION_CNTRL_M_IOCS3 0x08 +#define PI_FUNCTION_CNTRL_M_MEMCS0 0x10 +#define PI_FUNCTION_CNTRL_M_MEMCS1 0x20 +#define PI_FUNCTION_CNTRL_M_DMA 0x80 /* Define the bits in the slot control register. */ @@ -1540,6 +1554,10 @@ typedef union #define PI_BURST_HOLDOFF_V_RESERVED 1 #define PI_BURST_HOLDOFF_V_MEM_MAP 0 +/* Define the implicit mask of the Memory Address Mask Register. */ + +#define PI_MEM_ADD_MASK_M 0x3ff + /* * Define the fields in the IO Compare registers. * The driver must initialize the slot field with the slot ID shifted by the @@ -1577,6 +1595,7 @@ typedef union #define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */ #define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */ #define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */ +#define DEFEA_PROD_ID_4 0x0430A310 /* DEC product 300, rev 4 */ /**********************************************/ /* Digital PFI Specification v1.0 Definitions */ @@ -1633,12 +1652,6 @@ typedef union #define PFI_STATUS_V_FIFO_EMPTY 1 #define PFI_STATUS_V_DMA_IN_PROGRESS 0 -#define DFX_MAX_EISA_SLOTS 16 /* maximum number of EISA slots to scan */ -#define DFX_MAX_NUM_BOARDS 8 /* maximum number of adapters supported */ - -#define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */ -#define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */ - #define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */ #define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */ #define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */ @@ -1756,10 +1769,11 @@ typedef struct DFX_board_tag /* Store device, bus-specific, and parameter information for this adapter */ struct net_device *dev; /* pointer to device structure */ - struct net_device *next; - u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ - u16 base_addr; /* base I/O address (same as dev->base_addr) */ - struct pci_dev * pci_dev; + union { + void __iomem *mem; + int port; + } base; /* base address */ + struct device *bus_dev; u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */ u32 req_ttrt; /* requested TTRT value (in 80ns units) */ u32 burst_size; /* adapter burst size (enumerated) */ diff --git a/trunk/drivers/net/e2100.c b/trunk/drivers/net/e2100.c index c62d9c6363c6..b2b0a96218ca 100644 --- a/trunk/drivers/net/e2100.c +++ b/trunk/drivers/net/e2100.c @@ -355,8 +355,7 @@ e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring mem_on(ioaddr, shared_mem, (ring_offset>>8)); - /* Packet is always in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, ei_status.mem + (ring_offset & 0xff), count, 0); + memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count); mem_off(ioaddr); } diff --git a/trunk/drivers/net/es3210.c b/trunk/drivers/net/es3210.c index 2d2ea94a00bb..822e5bfd1a71 100644 --- a/trunk/drivers/net/es3210.c +++ b/trunk/drivers/net/es3210.c @@ -375,7 +375,7 @@ static void es_block_input(struct net_device *dev, int count, struct sk_buff *sk memcpy_fromio(skb->data + semi_count, ei_status.mem, count); } else { /* Packet is in one chunk. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } } diff --git a/trunk/drivers/net/macsonic.c b/trunk/drivers/net/macsonic.c index 24f6050fbf33..8ca57a0a4c11 100644 --- a/trunk/drivers/net/macsonic.c +++ b/trunk/drivers/net/macsonic.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/net/mv643xx_eth.c b/trunk/drivers/net/mv643xx_eth.c index b3bf86422734..d98e53efa2ef 100644 --- a/trunk/drivers/net/mv643xx_eth.c +++ b/trunk/drivers/net/mv643xx_eth.c @@ -2780,7 +2780,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = { .get_link = mv643xx_eth_get_link, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_strings = mv643xx_get_strings, .get_stats_count = mv643xx_get_stats_count, .get_ethtool_stats = mv643xx_get_ethtool_stats, .get_strings = mv643xx_get_strings, diff --git a/trunk/drivers/net/r8169.c b/trunk/drivers/net/r8169.c index 577babd4c938..5598d86380b4 100644 --- a/trunk/drivers/net/r8169.c +++ b/trunk/drivers/net/r8169.c @@ -2016,7 +2016,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, if (!skb) goto err_out; - skb_reserve(skb, (align - 1) & (u32)skb->data); + skb_reserve(skb, (align - 1) & (unsigned long)skb->data); *sk_buff = skb; mapping = pci_map_single(pdev, skb->data, rx_buf_sz, @@ -2487,7 +2487,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, skb = dev_alloc_skb(pkt_size + align); if (skb) { - skb_reserve(skb, (align - 1) & (u32)skb->data); + skb_reserve(skb, (align - 1) & (unsigned long)skb->data); eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0); *sk_buff = skb; rtl8169_mark_to_asic(desc, rx_buf_sz); diff --git a/trunk/drivers/net/s2io.c b/trunk/drivers/net/s2io.c index 639fbc0f16f3..8646b64994ab 100644 --- a/trunk/drivers/net/s2io.c +++ b/trunk/drivers/net/s2io.c @@ -7298,7 +7298,7 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) { struct iphdr *ip = lro->iph; struct tcphdr *tcp = lro->tcph; - u16 nchk; + __sum16 nchk; struct stat_block *statinfo = sp->mac_control.stats_info; DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); diff --git a/trunk/drivers/net/s2io.h b/trunk/drivers/net/s2io.h index a5e1a513deb5..0de0c65f945a 100644 --- a/trunk/drivers/net/s2io.h +++ b/trunk/drivers/net/s2io.h @@ -727,12 +727,12 @@ struct lro { struct iphdr *iph; struct tcphdr *tcph; u32 tcp_next_seq; - u32 tcp_ack; + __be32 tcp_ack; int total_len; int frags_len; int sg_num; int in_use; - u16 window; + __be16 window; u32 cur_tsval; u32 cur_tsecr; u8 saw_ts; @@ -1005,7 +1005,7 @@ static int s2io_set_swapper(struct s2io_nic * sp); static void s2io_card_down(struct s2io_nic *nic); static int s2io_card_up(struct s2io_nic *nic); static int get_xena_rev_id(struct pci_dev *pdev); -static int wait_for_cmd_complete(void *addr, u64 busy_bit); +static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit); static int s2io_add_isr(struct s2io_nic * sp); static void s2io_rem_isr(struct s2io_nic * sp); diff --git a/trunk/drivers/net/slip.c b/trunk/drivers/net/slip.c index a0806d262fc6..2f4b1de7a2b4 100644 --- a/trunk/drivers/net/slip.c +++ b/trunk/drivers/net/slip.c @@ -1343,15 +1343,12 @@ static int __init slip_init(void) printk(KERN_INFO "SLIP linefill/keepalive option.\n"); #endif - slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); + slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); if (!slip_devs) { printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n"); return -ENOMEM; } - /* Clear the pointer array, we allocate devices when we need them */ - memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev); - /* Fill in our line protocol discipline, and register it */ if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); diff --git a/trunk/drivers/net/smc-mca.c b/trunk/drivers/net/smc-mca.c index 7122932eac90..ae1ae343beed 100644 --- a/trunk/drivers/net/smc-mca.c +++ b/trunk/drivers/net/smc-mca.c @@ -482,8 +482,7 @@ static void ultramca_block_input(struct net_device *dev, int count, struct sk_bu count -= semi_count; memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } } diff --git a/trunk/drivers/net/smc-ultra.c b/trunk/drivers/net/smc-ultra.c index d70bc9795346..a52b22d7db65 100644 --- a/trunk/drivers/net/smc-ultra.c +++ b/trunk/drivers/net/smc-ultra.c @@ -454,8 +454,7 @@ ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ri count -= semi_count; memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ diff --git a/trunk/drivers/net/smc-ultra32.c b/trunk/drivers/net/smc-ultra32.c index 2c5319c62fa5..88a30e56c64c 100644 --- a/trunk/drivers/net/smc-ultra32.c +++ b/trunk/drivers/net/smc-ultra32.c @@ -395,8 +395,7 @@ static void ultra32_block_input(struct net_device *dev, memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } } diff --git a/trunk/drivers/net/spider_net.c b/trunk/drivers/net/spider_net.c index bf6ff39e02bb..64ed8ff5b03a 100644 --- a/trunk/drivers/net/spider_net.c +++ b/trunk/drivers/net/spider_net.c @@ -1907,7 +1907,7 @@ spider_net_stop(struct net_device *netdev) spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0); /* free_irq(netdev->irq, netdev);*/ - free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev); + free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev); spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, SPIDER_NET_DMA_TX_FEND_VALUE); diff --git a/trunk/drivers/net/tg3.c b/trunk/drivers/net/tg3.c index 135c0987deae..e136bae61970 100644 --- a/trunk/drivers/net/tg3.c +++ b/trunk/drivers/net/tg3.c @@ -3380,7 +3380,7 @@ static int tg3_rx(struct tg3 *tp, int budget) } next_pkt_nopost: sw_idx++; - sw_idx %= TG3_RX_RCB_RING_SIZE(tp); + sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1); /* Refresh hw_idx to see if there is new work */ if (sw_idx == hw_idx) { diff --git a/trunk/drivers/net/ucc_geth.c b/trunk/drivers/net/ucc_geth.c index abb8611c5a91..31c97a6591a4 100644 --- a/trunk/drivers/net/ucc_geth.c +++ b/trunk/drivers/net/ucc_geth.c @@ -1709,75 +1709,13 @@ static void adjust_link(struct net_device *dev) if (mii_info->speed != ugeth->oldspeed) { switch (mii_info->speed) { case 1000: -#ifdef CONFIG_PPC_MPC836x -/* FIXME: This code is for 100Mbs BUG fixing, -remove this when it is fixed!!! */ - if (ugeth->ug_info->enet_interface == - ENET_1000_GMII) - /* Run the commands which initialize the PHY */ - { - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, 0x1b); - tempval |= 0x000f; - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, 0x1b, - (u16) tempval); - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, - MII_BMCR); - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, MII_BMCR, - (u16) (tempval | BMCR_RESET)); - } else if (ugeth->ug_info->enet_interface == - ENET_1000_RGMII) - /* Run the commands which initialize the PHY */ - { - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, 0x1b); - tempval = (tempval & ~0x000f) | 0x000b; - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, 0x1b, - (u16) tempval); - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, - MII_BMCR); - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, MII_BMCR, - (u16) (tempval | BMCR_RESET)); - } - msleep(4000); -#endif /* CONFIG_MPC8360 */ - adjust_enet_interface(ugeth); + ugeth->ug_info->enet_interface = ENET_1000_RGMII; break; case 100: - case 10: -#ifdef CONFIG_PPC_MPC836x -/* FIXME: This code is for 100Mbs BUG fixing, -remove this lines when it will be fixed!!! */ ugeth->ug_info->enet_interface = ENET_100_RGMII; - tempval = - (u32) mii_info->mdio_read(ugeth->dev, - mii_info->mii_id, - 0x1b); - tempval = (tempval & ~0x000f) | 0x000b; - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, 0x1b, - (u16) tempval); - tempval = - (u32) mii_info->mdio_read(ugeth->dev, - mii_info->mii_id, - MII_BMCR); - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, MII_BMCR, - (u16) (tempval | - BMCR_RESET)); - msleep(4000); -#endif /* CONFIG_MPC8360 */ - adjust_enet_interface(ugeth); + break; + case 10: + ugeth->ug_info->enet_interface = ENET_10_RGMII; break; default: ugeth_warn @@ -1785,6 +1723,7 @@ remove this lines when it will be fixed!!! */ dev->name, mii_info->speed); break; } + adjust_enet_interface(ugeth); ugeth_info("%s: Speed %dBT", dev->name, mii_info->speed); @@ -4133,6 +4072,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma static int mii_mng_configured = 0; const phandle *ph; const unsigned int *prop; + const void *mac_addr; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -4258,7 +4198,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ugeth->ug_info = ug_info; ugeth->dev = dev; - memcpy(dev->dev_addr, get_property(np, "mac-address", NULL), 6); + + mac_addr = get_property(np, "mac-address", NULL); + if (mac_addr == NULL) + mac_addr = get_property(np, "local-mac-address", NULL); + if (mac_addr) + memcpy(dev->dev_addr, mac_addr, 6); return 0; } diff --git a/trunk/drivers/net/ucc_geth_phy.c b/trunk/drivers/net/ucc_geth_phy.c index 3c86592ce03c..6fda6d88be49 100644 --- a/trunk/drivers/net/ucc_geth_phy.c +++ b/trunk/drivers/net/ucc_geth_phy.c @@ -376,6 +376,8 @@ static int marvell_init(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); ucc_geth_phy_write(mii_info, 0x14, 0x0cd2); + ucc_geth_phy_write(mii_info, 0x1b, + (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b); ucc_geth_phy_write(mii_info, MII_BMCR, ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); msleep(4000); diff --git a/trunk/drivers/net/wan/pc300too.c b/trunk/drivers/net/wan/pc300too.c index 79b2d5454d6b..bc156b51678a 100644 --- a/trunk/drivers/net/wan/pc300too.c +++ b/trunk/drivers/net/wan/pc300too.c @@ -101,8 +101,8 @@ typedef struct port_s { typedef struct card_s { int type; /* RSV, X21, etc. */ int n_ports; /* 1 or 2 ports */ - u8* __iomem rambase; /* buffer memory base (virtual) */ - u8* __iomem scabase; /* SCA memory base (virtual) */ + u8 __iomem *rambase; /* buffer memory base (virtual) */ + u8 __iomem *scabase; /* SCA memory base (virtual) */ plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */ u32 init_ctrl_value; /* Saved value - 9050 bug workaround */ u16 rx_ring_buffers; /* number of buffers in a ring */ @@ -134,7 +134,7 @@ typedef struct card_s { static void pc300_set_iface(port_t *port) { card_t *card = port->card; - u32* init_ctrl = &card->plxbase->init_ctrl; + u32 __iomem * init_ctrl = &card->plxbase->init_ctrl; u16 msci = get_msci(port); u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; @@ -393,7 +393,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, /* PLX PCI 9050 workaround for local configuration register read bug */ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys); - card->init_ctrl_value = readl(&((plx9050*)card->scabase)->init_ctrl); + card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl); pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys); /* Reset PLX */ @@ -519,10 +519,10 @@ static struct pci_device_id pc300_pci_tbl[] __devinitdata = { static struct pci_driver pc300_pci_driver = { - name: "PC300", - id_table: pc300_pci_tbl, - probe: pc300_pci_init_one, - remove: pc300_pci_remove_one, + .name = "PC300", + .id_table = pc300_pci_tbl, + .probe = pc300_pci_init_one, + .remove = pc300_pci_remove_one, }; diff --git a/trunk/drivers/net/wd.c b/trunk/drivers/net/wd.c index 7f38012b9c92..a0326818ff2f 100644 --- a/trunk/drivers/net/wd.c +++ b/trunk/drivers/net/wd.c @@ -433,7 +433,7 @@ wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_ memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } /* Turn off 16 bit access so that reboot works. ISA brain-damage */ diff --git a/trunk/drivers/pcmcia/m32r_pcc.c b/trunk/drivers/pcmcia/m32r_pcc.c index bbf025874d0c..4dbef0762376 100644 --- a/trunk/drivers/pcmcia/m32r_pcc.c +++ b/trunk/drivers/pcmcia/m32r_pcc.c @@ -722,7 +722,7 @@ static int __init init_m32r_pcc(void) /* Set up interrupt handler(s) */ for (i = 0 ; i < pcc_sockets ; i++) { - socket[i].socket.dev.dev = &pcc_device.dev; + socket[i].socket.dev.parent = &pcc_device.dev; socket[i].socket.ops = &pcc_operations; socket[i].socket.resource_ops = &pccard_static_ops; socket[i].socket.owner = THIS_MODULE; diff --git a/trunk/drivers/rtc/rtc-dev.c b/trunk/drivers/rtc/rtc-dev.c index 94d3df62a5fa..82f2ac87ccd4 100644 --- a/trunk/drivers/rtc/rtc-dev.c +++ b/trunk/drivers/rtc/rtc-dev.c @@ -305,7 +305,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, case RTC_IRQP_READ: if (ops->irq_set_freq) - err = put_user(rtc->irq_freq, (unsigned long *) arg); + err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); break; case RTC_IRQP_SET: diff --git a/trunk/drivers/rtc/rtc-pcf8563.c b/trunk/drivers/rtc/rtc-pcf8563.c index 4b72b8ef5d66..038118bbfaea 100644 --- a/trunk/drivers/rtc/rtc-pcf8563.c +++ b/trunk/drivers/rtc/rtc-pcf8563.c @@ -53,6 +53,25 @@ I2C_CLIENT_INSMOD; #define PCF8563_SC_LV 0x80 /* low voltage */ #define PCF8563_MO_C 0x80 /* century */ +struct pcf8563 { + struct i2c_client client; + /* + * The meaning of MO_C bit varies by the chip type. + * From PCF8563 datasheet: this bit is toggled when the years + * register overflows from 99 to 00 + * 0 indicates the century is 20xx + * 1 indicates the century is 19xx + * From RTC8564 datasheet: this bit indicates change of + * century. When the year digit data overflows from 99 to 00, + * this bit is set. By presetting it to 0 while still in the + * 20th century, it will be set in year 2000, ... + * There seems no reliable way to know how the system use this + * bit. So let's do it heuristically, assuming we are live in + * 1970...2069. + */ + int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ +}; + static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind); static int pcf8563_detach(struct i2c_client *client); @@ -62,6 +81,7 @@ static int pcf8563_detach(struct i2c_client *client); */ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) { + struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); unsigned char buf[13] = { PCF8563_REG_ST1 }; struct i2c_msg msgs[] = { @@ -94,8 +114,12 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F); tm->tm_wday = buf[PCF8563_REG_DW] & 0x07; tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ - tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]) - + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 0 : 100); + tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]); + if (tm->tm_year < 70) + tm->tm_year += 100; /* assume we are in 1970...2069 */ + /* detect the polarity heuristically. see note above. */ + pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ? + (tm->tm_year >= 100) : (tm->tm_year < 100); dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", @@ -114,6 +138,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) { + struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); int i, err; unsigned char buf[9]; @@ -135,7 +160,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) /* year and century */ buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100); - if (tm->tm_year < 100) + if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100)) buf[PCF8563_REG_MO] |= PCF8563_MO_C; buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; @@ -248,6 +273,7 @@ static struct i2c_driver pcf8563_driver = { static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) { + struct pcf8563 *pcf8563; struct i2c_client *client; struct rtc_device *rtc; @@ -260,11 +286,12 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) goto exit; } - if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { + if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) { err = -ENOMEM; goto exit; } + client = &pcf8563->client; client->addr = address; client->driver = &pcf8563_driver; client->adapter = adapter; @@ -301,7 +328,7 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) i2c_detach_client(client); exit_kfree: - kfree(client); + kfree(pcf8563); exit: return err; @@ -309,6 +336,7 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) static int pcf8563_detach(struct i2c_client *client) { + struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); int err; struct rtc_device *rtc = i2c_get_clientdata(client); @@ -318,7 +346,7 @@ static int pcf8563_detach(struct i2c_client *client) if ((err = i2c_detach_client(client))) return err; - kfree(client); + kfree(pcf8563); return 0; } diff --git a/trunk/drivers/s390/char/monreader.c b/trunk/drivers/s390/char/monreader.c index a138b1510093..3a1a958fb5f2 100644 --- a/trunk/drivers/s390/char/monreader.c +++ b/trunk/drivers/s390/char/monreader.c @@ -3,7 +3,7 @@ * * Character device driver for reading z/VM *MONITOR service records. * - * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. + * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. * * Author: Gerald Schaefer */ @@ -22,7 +22,7 @@ #include #include #include -#include "../net/iucv.h" +#include //#define MON_DEBUG /* Debug messages on/off */ @@ -50,14 +50,13 @@ static char mon_dcss_name[9] = "MONDCSS\0"; struct mon_msg { u32 pos; u32 mca_offset; - iucv_MessagePending local_eib; + struct iucv_message msg; char msglim_reached; char replied_msglim; }; struct mon_private { - u16 pathid; - iucv_handle_t iucv_handle; + struct iucv_path *path; struct mon_msg *msg_array[MON_MSGLIM]; unsigned int write_index; unsigned int read_index; @@ -75,8 +74,6 @@ static unsigned long mon_dcss_end; static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue); static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue); -static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - static u8 user_data_connect[16] = { /* Version code, must be 0x01 for shared mode */ 0x01, @@ -100,8 +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 inline void dcss_mkname(char *ascii_name, char *ebcdic_name) { int i; @@ -119,8 +115,7 @@ dcss_mkname(char *ascii_name, char *ebcdic_name) * print appropriate error message for segment_load()/segment_type() * return code */ -static void -mon_segment_warn(int rc, char* seg_name) +static void mon_segment_warn(int rc, char* seg_name) { switch (rc) { case -ENOENT: @@ -166,44 +161,37 @@ mon_segment_warn(int rc, char* seg_name) } } -static inline unsigned long -mon_mca_start(struct mon_msg *monmsg) +static inline unsigned long mon_mca_start(struct mon_msg *monmsg) { - return monmsg->local_eib.ln1msg1.iprmmsg1_u32; + return *(u32 *) &monmsg->msg.rmmsg; } -static inline unsigned long -mon_mca_end(struct mon_msg *monmsg) +static inline unsigned long mon_mca_end(struct mon_msg *monmsg) { - return monmsg->local_eib.ln1msg2.ipbfln1f; + return *(u32 *) &monmsg->msg.rmmsg[4]; } -static inline u8 -mon_mca_type(struct mon_msg *monmsg, u8 index) +static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index) { return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index); } -static inline u32 -mon_mca_size(struct mon_msg *monmsg) +static inline u32 mon_mca_size(struct mon_msg *monmsg) { return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1; } -static inline u32 -mon_rec_start(struct mon_msg *monmsg) +static inline u32 mon_rec_start(struct mon_msg *monmsg) { return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4)); } -static inline u32 -mon_rec_end(struct mon_msg *monmsg) +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 inline int mon_check_mca(struct mon_msg *monmsg) { if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) || (mon_rec_start(monmsg) < mon_dcss_start) || @@ -221,20 +209,17 @@ mon_check_mca(struct mon_msg *monmsg) return 0; } -static inline int -mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv) +static inline int mon_send_reply(struct mon_msg *monmsg, + struct mon_private *monpriv) { - u8 prmmsg[8]; int rc; P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " "0x%08X\n\n", - monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls); - rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid, - monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls, - 0, prmmsg); + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); + + rc = iucv_message_reply(monpriv->path, &monmsg->msg, + IUCV_IPRMDATA, NULL, 0); atomic_dec(&monpriv->msglim_count); if (likely(!monmsg->msglim_reached)) { monmsg->pos = 0; @@ -251,10 +236,19 @@ mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv) return 0; } -static inline struct mon_private * -mon_alloc_mem(void) +static inline void mon_free_mem(struct mon_private *monpriv) +{ + int i; + + for (i = 0; i < MON_MSGLIM; i++) + if (monpriv->msg_array[i]) + kfree(monpriv->msg_array[i]); + kfree(monpriv); +} + +static inline struct mon_private *mon_alloc_mem(void) { - int i,j; + int i; struct mon_private *monpriv; monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); @@ -267,16 +261,15 @@ mon_alloc_mem(void) GFP_KERNEL); if (!monpriv->msg_array[i]) { P_ERROR("open, no memory for msg_array\n"); - for (j = 0; j < i; j++) - kfree(monpriv->msg_array[j]); + mon_free_mem(monpriv); return NULL; } } return monpriv; } -static inline void -mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) +static inline void mon_read_debug(struct mon_msg *monmsg, + struct mon_private *monpriv) { #ifdef MON_DEBUG u8 msg_type[2], mca_type; @@ -284,7 +277,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; - memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2); + memcpy(msg_type, &monmsg->msg.class, 2); EBCASC(msg_type, 2); mca_type = mon_mca_type(monmsg, 0); EBCASC(&mca_type, 1); @@ -292,8 +285,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n", monpriv->read_index, monpriv->write_index); P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n", - monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls); + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n", msg_type[0], msg_type[1], mca_type ? mca_type : 'X', mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2)); @@ -306,8 +298,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) #endif } -static inline void -mon_next_mca(struct mon_msg *monmsg) +static inline void mon_next_mca(struct mon_msg *monmsg) { if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) return; @@ -316,8 +307,7 @@ mon_next_mca(struct mon_msg *monmsg) monmsg->pos = 0; } -static inline struct mon_msg * -mon_next_message(struct mon_private *monpriv) +static inline struct mon_msg *mon_next_message(struct mon_private *monpriv) { struct mon_msg *monmsg; @@ -342,39 +332,37 @@ mon_next_message(struct mon_private *monpriv) /****************************************************************************** * IUCV handler * *****************************************************************************/ -static void -mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data) +static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; P_DEBUG("IUCV connection completed\n"); P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = " "0x%02X, Sample = 0x%02X\n", - eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]); + ipuser[0], ipuser[1], ipuser[2]); atomic_set(&monpriv->iucv_connected, 1); wake_up(&mon_conn_wait_queue); } -static void -mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data) +static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; - P_ERROR("IUCV connection severed with rc = 0x%X\n", - (u8) eib->ipuser[0]); + P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]); + iucv_path_sever(path, NULL); atomic_set(&monpriv->iucv_severed, 1); wake_up(&mon_conn_wait_queue); wake_up_interruptible(&mon_read_wait_queue); } -static void -mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data) +static void mon_iucv_message_pending(struct iucv_path *path, + struct iucv_message *msg) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; P_DEBUG("IUCV message pending\n"); - memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib, - sizeof(iucv_MessagePending)); + memcpy(&monpriv->msg_array[monpriv->write_index]->msg, + msg, sizeof(*msg)); if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { P_WARNING("IUCV message pending, message limit (%i) reached\n", MON_MSGLIM); @@ -385,54 +373,45 @@ mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data) wake_up_interruptible(&mon_read_wait_queue); } -static iucv_interrupt_ops_t mon_iucvops = { - .ConnectionComplete = mon_iucv_ConnectionComplete, - .ConnectionSevered = mon_iucv_ConnectionSevered, - .MessagePending = mon_iucv_MessagePending, +static struct iucv_handler monreader_iucv_handler = { + .path_complete = mon_iucv_path_complete, + .path_severed = mon_iucv_path_severed, + .message_pending = mon_iucv_message_pending, }; /****************************************************************************** * file operations * *****************************************************************************/ -static int -mon_open(struct inode *inode, struct file *filp) +static int mon_open(struct inode *inode, struct file *filp) { - int rc, i; struct mon_private *monpriv; + int rc; /* * only one user allowed */ + rc = -EBUSY; if (test_and_set_bit(MON_IN_USE, &mon_in_use)) - return -EBUSY; + goto out; + rc = -ENOMEM; monpriv = mon_alloc_mem(); if (!monpriv) - return -ENOMEM; + goto out_use; /* - * Register with IUCV and connect to *MONITOR service + * Connect to *MONITOR service */ - monpriv->iucv_handle = iucv_register_program("my_monreader ", - MON_SERVICE, - NULL, - &mon_iucvops, - monpriv); - if (!monpriv->iucv_handle) { - P_ERROR("failed to register with iucv driver\n"); - rc = -EIO; - goto out_error; - } - P_INFO("open, registered with IUCV\n"); - - rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect, - MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL, - monpriv->iucv_handle, NULL); + monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); + if (!monpriv->path) + goto out_priv; + rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, + MON_SERVICE, NULL, user_data_connect, monpriv); if (rc) { P_ERROR("iucv connection to *MONITOR failed with " "IPUSER SEVER code = %i\n", rc); rc = -EIO; - goto out_unregister; + goto out_path; } /* * Wait for connection confirmation @@ -444,24 +423,23 @@ mon_open(struct inode *inode, struct file *filp) atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); rc = -EIO; - goto out_unregister; + goto out_path; } P_INFO("open, established connection to *MONITOR service\n\n"); filp->private_data = monpriv; return nonseekable_open(inode, filp); -out_unregister: - iucv_unregister_program(monpriv->iucv_handle); -out_error: - for (i = 0; i < MON_MSGLIM; i++) - kfree(monpriv->msg_array[i]); - kfree(monpriv); +out_path: + kfree(monpriv->path); +out_priv: + mon_free_mem(monpriv); +out_use: clear_bit(MON_IN_USE, &mon_in_use); +out: return rc; } -static int -mon_close(struct inode *inode, struct file *filp) +static int mon_close(struct inode *inode, struct file *filp) { int rc, i; struct mon_private *monpriv = filp->private_data; @@ -469,18 +447,12 @@ mon_close(struct inode *inode, struct file *filp) /* * Close IUCV connection and unregister */ - rc = iucv_sever(monpriv->pathid, user_data_sever); + rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) P_ERROR("close, iucv_sever failed with rc = %i\n", rc); else P_INFO("close, terminated connection to *MONITOR service\n"); - rc = iucv_unregister_program(monpriv->iucv_handle); - if (rc) - P_ERROR("close, iucv_unregister failed with rc = %i\n", rc); - else - P_INFO("close, unregistered with IUCV\n"); - atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); atomic_set(&monpriv->read_ready, 0); @@ -495,8 +467,8 @@ mon_close(struct inode *inode, struct file *filp) return 0; } -static ssize_t -mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) +static ssize_t mon_read(struct file *filp, char __user *data, + size_t count, loff_t *ppos) { struct mon_private *monpriv = filp->private_data; struct mon_msg *monmsg; @@ -563,8 +535,7 @@ mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) return count; } -static unsigned int -mon_poll(struct file *filp, struct poll_table_struct *p) +static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p) { struct mon_private *monpriv = filp->private_data; @@ -593,8 +564,7 @@ static struct miscdevice mon_dev = { /****************************************************************************** * module init/exit * *****************************************************************************/ -static int __init -mon_init(void) +static int __init mon_init(void) { int rc; @@ -603,22 +573,34 @@ mon_init(void) return -ENODEV; } + /* + * Register with IUCV and connect to *MONITOR service + */ + rc = iucv_register(&monreader_iucv_handler, 1); + if (rc) { + P_ERROR("failed to register with iucv driver\n"); + return rc; + } + P_INFO("open, registered with IUCV\n"); + rc = segment_type(mon_dcss_name); if (rc < 0) { mon_segment_warn(rc, mon_dcss_name); - return rc; + goto out_iucv; } if (rc != SEG_TYPE_SC) { P_ERROR("segment %s has unsupported type, should be SC\n", mon_dcss_name); - return -EINVAL; + rc = -EINVAL; + goto out_iucv; } rc = segment_load(mon_dcss_name, SEGMENT_SHARED, &mon_dcss_start, &mon_dcss_end); if (rc < 0) { mon_segment_warn(rc, mon_dcss_name); - return -EINVAL; + rc = -EINVAL; + goto out_iucv; } dcss_mkname(mon_dcss_name, &user_data_connect[8]); @@ -634,14 +616,16 @@ mon_init(void) out: segment_unload(mon_dcss_name); +out_iucv: + iucv_unregister(&monreader_iucv_handler, 1); return rc; } -static void __exit -mon_exit(void) +static void __exit mon_exit(void) { segment_unload(mon_dcss_name); WARN_ON(misc_deregister(&mon_dev) != 0); + iucv_unregister(&monreader_iucv_handler, 1); return; } diff --git a/trunk/drivers/s390/char/vmlogrdr.c b/trunk/drivers/s390/char/vmlogrdr.c index 4f894dc2373b..8432a76b961e 100644 --- a/trunk/drivers/s390/char/vmlogrdr.c +++ b/trunk/drivers/s390/char/vmlogrdr.c @@ -3,7 +3,7 @@ * character device driver for reading z/VM system service records * * - * Copyright (C) 2004 IBM Corporation + * Copyright 2004 IBM Corporation * character device driver for reading z/VM system service records, * Version 1.0 * Author(s): Xenia Tkatschow @@ -21,7 +21,7 @@ #include #include #include -#include "../net/iucv.h" +#include #include #include #include @@ -60,12 +60,11 @@ struct vmlogrdr_priv_t { char system_service[8]; char internal_name[8]; char recording_name[8]; - u16 pathid; + struct iucv_path *path; int connection_established; int iucv_path_severed; - iucv_MessagePending local_interrupt_buffer; + struct iucv_message local_interrupt_buffer; atomic_t receive_ready; - iucv_handle_t iucv_handle; int minor_num; char * buffer; char * current_position; @@ -97,37 +96,19 @@ static struct file_operations vmlogrdr_fops = { }; -static u8 iucvMagic[16] = { - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 -}; +static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]); +static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]); +static void vmlogrdr_iucv_message_pending(struct iucv_path *, + struct iucv_message *); -static u8 mask[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +static struct iucv_handler vmlogrdr_iucv_handler = { + .path_complete = vmlogrdr_iucv_path_complete, + .path_severed = vmlogrdr_iucv_path_severed, + .message_pending = vmlogrdr_iucv_message_pending, }; -static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - -static void -vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data); -static void -vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data); -static void -vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data); - - -static iucv_interrupt_ops_t vmlogrdr_iucvops = { - .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete, - .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered, - .MessagePending = vmlogrdr_iucv_MessagePending, -}; - static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); @@ -176,28 +157,29 @@ static struct cdev *vmlogrdr_cdev = NULL; static int recording_class_AB; -static void -vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib, - void * pgm_data) +static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; + spin_lock(&logptr->priv_lock); logptr->connection_established = 1; spin_unlock(&logptr->priv_lock); wake_up(&conn_wait_queue); - return; } -static void -vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) +static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { - u8 reason = (u8) eib->ipuser[8]; - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; + u8 reason = (u8) ipuser[8]; printk (KERN_ERR "vmlogrdr: connection severed with" " reason %i\n", reason); + iucv_path_sever(path, NULL); + kfree(path); + logptr->path = NULL; + spin_lock(&logptr->priv_lock); logptr->connection_established = 0; logptr->iucv_path_severed = 1; @@ -209,10 +191,10 @@ vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) } -static void -vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) +static void vmlogrdr_iucv_message_pending(struct iucv_path *path, + struct iucv_message *msg) { - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; /* * This function is the bottom half so it should be quick. @@ -220,15 +202,15 @@ vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) * the usage count */ spin_lock(&logptr->priv_lock); - memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib)); + memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg)); atomic_inc(&logptr->receive_ready); spin_unlock(&logptr->priv_lock); wake_up_interruptible(&read_wait_queue); } -static int -vmlogrdr_get_recording_class_AB(void) { +static int vmlogrdr_get_recording_class_AB(void) +{ char cp_command[]="QUERY COMMAND RECORDING "; char cp_response[80]; char *tail; @@ -258,8 +240,9 @@ vmlogrdr_get_recording_class_AB(void) { } -static int -vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { +static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, + int action, int purge) +{ char cp_command[80]; char cp_response[160]; @@ -317,8 +300,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { } -static int -vmlogrdr_open (struct inode *inode, struct file *filp) +static int vmlogrdr_open (struct inode *inode, struct file *filp) { int dev_num = 0; struct vmlogrdr_priv_t * logptr = NULL; @@ -328,10 +310,7 @@ vmlogrdr_open (struct inode *inode, struct file *filp) dev_num = iminor(inode); if (dev_num > MAXMINOR) return -ENODEV; - logptr = &sys_ser[dev_num]; - if (logptr == NULL) - return -ENODEV; /* * only allow for blocking reads to be open @@ -344,52 +323,38 @@ vmlogrdr_open (struct inode *inode, struct file *filp) if (logptr->dev_in_use) { spin_unlock_bh(&logptr->priv_lock); return -EBUSY; - } else { - logptr->dev_in_use = 1; - spin_unlock_bh(&logptr->priv_lock); } - + logptr->dev_in_use = 1; + logptr->connection_established = 0; + logptr->iucv_path_severed = 0; atomic_set(&logptr->receive_ready, 0); logptr->buffer_free = 1; + spin_unlock_bh(&logptr->priv_lock); /* set the file options */ filp->private_data = logptr; filp->f_op = &vmlogrdr_fops; /* start recording for this service*/ - ret=0; - if (logptr->autorecording) + if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,1,logptr->autopurge); - if (ret) - printk (KERN_WARNING "vmlogrdr: failed to start " - "recording automatically\n"); - - /* Register with iucv driver */ - logptr->iucv_handle = iucv_register_program(iucvMagic, - logptr->system_service, mask, &vmlogrdr_iucvops, - logptr); - - if (logptr->iucv_handle == NULL) { - printk (KERN_ERR "vmlogrdr: failed to register with" - "iucv driver\n"); - goto not_registered; + if (ret) + printk (KERN_WARNING "vmlogrdr: failed to start " + "recording automatically\n"); } /* create connection to the system service */ - spin_lock_bh(&logptr->priv_lock); - logptr->connection_established = 0; - logptr->iucv_path_severed = 0; - spin_unlock_bh(&logptr->priv_lock); - - connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic, - logptr->system_service, iucv_host, 0, - NULL, NULL, - logptr->iucv_handle, NULL); + logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL); + if (!logptr->path) + goto out_dev; + connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler, + logptr->system_service, NULL, NULL, + logptr); if (connect_rc) { printk (KERN_ERR "vmlogrdr: iucv connection to %s " "failed with rc %i \n", logptr->system_service, connect_rc); - goto not_connected; + goto out_path; } /* We've issued the connect and now we must wait for a @@ -398,35 +363,28 @@ vmlogrdr_open (struct inode *inode, struct file *filp) */ wait_event(conn_wait_queue, (logptr->connection_established) || (logptr->iucv_path_severed)); - if (logptr->iucv_path_severed) { - goto not_connected; - } - + if (logptr->iucv_path_severed) + goto out_record; return nonseekable_open(inode, filp); -not_connected: - iucv_unregister_program(logptr->iucv_handle); - logptr->iucv_handle = NULL; -not_registered: +out_record: if (logptr->autorecording) vmlogrdr_recording(logptr,0,logptr->autopurge); +out_path: + kfree(logptr->path); /* kfree(NULL) is ok. */ + logptr->path = NULL; +out_dev: logptr->dev_in_use = 0; return -EIO; - - } -static int -vmlogrdr_release (struct inode *inode, struct file *filp) +static int vmlogrdr_release (struct inode *inode, struct file *filp) { int ret; struct vmlogrdr_priv_t * logptr = filp->private_data; - iucv_unregister_program(logptr->iucv_handle); - logptr->iucv_handle = NULL; - if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,0,logptr->autopurge); if (ret) @@ -439,8 +397,8 @@ vmlogrdr_release (struct inode *inode, struct file *filp) } -static int -vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { +static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) +{ int rc, *temp; /* we need to keep track of two data sizes here: * The number of bytes we need to receive from iucv and @@ -461,8 +419,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { * We need to return the total length of the record * + size of FENCE in the first 4 bytes of the buffer. */ - iucv_data_count = - priv->local_interrupt_buffer.ln1msg2.ipbfln1f; + iucv_data_count = priv->local_interrupt_buffer.length; user_data_count = sizeof(int); temp = (int*)priv->buffer; *temp= iucv_data_count + sizeof(FENCE); @@ -474,14 +431,10 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { */ if (iucv_data_count > NET_BUFFER_SIZE) iucv_data_count = NET_BUFFER_SIZE; - rc = iucv_receive(priv->pathid, - priv->local_interrupt_buffer.ipmsgid, - priv->local_interrupt_buffer.iptrgcls, - buffer, - iucv_data_count, - NULL, - NULL, - &priv->residual_length); + rc = iucv_message_receive(priv->path, + &priv->local_interrupt_buffer, + 0, buffer, iucv_data_count, + &priv->residual_length); spin_unlock_bh(&priv->priv_lock); /* An rc of 5 indicates that the record was bigger then * the buffer, which is OK for us. A 9 indicates that the @@ -513,8 +466,8 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { } -static ssize_t -vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) +static ssize_t vmlogrdr_read(struct file *filp, char __user *data, + size_t count, loff_t * ppos) { int rc; struct vmlogrdr_priv_t * priv = filp->private_data; @@ -546,8 +499,10 @@ vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) return count; } -static ssize_t -vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { +static ssize_t vmlogrdr_autopurge_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -565,8 +520,10 @@ vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, con } -static ssize_t -vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t vmlogrdr_autopurge_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autopurge); } @@ -576,8 +533,10 @@ static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show, vmlogrdr_autopurge_store); -static ssize_t -vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { +static ssize_t vmlogrdr_purge_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ char cp_command[80]; char cp_response[80]; @@ -617,9 +576,10 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store); -static ssize_t -vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) { +static ssize_t vmlogrdr_autorecording_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -637,8 +597,10 @@ vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, } -static ssize_t -vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t vmlogrdr_autorecording_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autorecording); } @@ -648,9 +610,10 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show, vmlogrdr_autorecording_store); -static ssize_t -vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { - +static ssize_t vmlogrdr_recording_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret; @@ -675,8 +638,9 @@ vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, con static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store); -static ssize_t -vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) { +static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver, + char *buf) +{ char cp_command[] = "QUERY RECORDING "; int len; @@ -709,52 +673,63 @@ static struct device_driver vmlogrdr_driver = { }; -static int -vmlogrdr_register_driver(void) { +static int vmlogrdr_register_driver(void) +{ int ret; + /* Register with iucv driver */ + ret = iucv_register(&vmlogrdr_iucv_handler, 1); + if (ret) { + printk (KERN_ERR "vmlogrdr: failed to register with" + "iucv driver\n"); + goto out; + } + ret = driver_register(&vmlogrdr_driver); if (ret) { printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); - return ret; + goto out_iucv; } ret = driver_create_file(&vmlogrdr_driver, &driver_attr_recording_status); if (ret) { printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); - goto unregdriver; + goto out_driver; } vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); if (IS_ERR(vmlogrdr_class)) { printk(KERN_ERR "vmlogrdr: failed to create class.\n"); - ret=PTR_ERR(vmlogrdr_class); - vmlogrdr_class=NULL; - goto unregattr; + ret = PTR_ERR(vmlogrdr_class); + vmlogrdr_class = NULL; + goto out_attr; } return 0; -unregattr: +out_attr: driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); -unregdriver: +out_driver: driver_unregister(&vmlogrdr_driver); +out_iucv: + iucv_unregister(&vmlogrdr_iucv_handler, 1); +out: return ret; } -static void -vmlogrdr_unregister_driver(void) { +static void vmlogrdr_unregister_driver(void) +{ class_destroy(vmlogrdr_class); vmlogrdr_class = NULL; driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); driver_unregister(&vmlogrdr_driver); - return; + iucv_unregister(&vmlogrdr_iucv_handler, 1); } -static int -vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { +static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) +{ struct device *dev; int ret; @@ -803,9 +778,10 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { } -static int -vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { - class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num)); +static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv) +{ + class_device_destroy(vmlogrdr_class, + MKDEV(vmlogrdr_major, priv->minor_num)); if (priv->device != NULL) { sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); device_unregister(priv->device); @@ -815,8 +791,8 @@ vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { } -static int -vmlogrdr_register_cdev(dev_t dev) { +static int vmlogrdr_register_cdev(dev_t dev) +{ int rc = 0; vmlogrdr_cdev = cdev_alloc(); if (!vmlogrdr_cdev) { @@ -836,9 +812,10 @@ vmlogrdr_register_cdev(dev_t dev) { } -static void -vmlogrdr_cleanup(void) { +static void vmlogrdr_cleanup(void) +{ int i; + if (vmlogrdr_cdev) { cdev_del(vmlogrdr_cdev); vmlogrdr_cdev=NULL; @@ -855,8 +832,7 @@ vmlogrdr_cleanup(void) { } -static int -vmlogrdr_init(void) +static int vmlogrdr_init(void) { int rc; int i; @@ -906,8 +882,7 @@ vmlogrdr_init(void) } -static void -vmlogrdr_exit(void) +static void vmlogrdr_exit(void) { vmlogrdr_cleanup(); printk (KERN_INFO "vmlogrdr: driver unloaded\n"); diff --git a/trunk/drivers/s390/net/Kconfig b/trunk/drivers/s390/net/Kconfig index 52625153a4f0..f98fa465df0a 100644 --- a/trunk/drivers/s390/net/Kconfig +++ b/trunk/drivers/s390/net/Kconfig @@ -22,13 +22,6 @@ config CTC available. This option is also available as a module which will be called ctc.ko. If you do not know what it is, it's safe to say "Y". -config IUCV - tristate "IUCV support (VM only)" - help - Select this option if you want to use inter-user communication - under VM or VIF. If unsure, say "Y" to enable a fast communication - link between VM guests. - config NETIUCV tristate "IUCV network device support (VM only)" depends on IUCV && NETDEVICES diff --git a/trunk/drivers/s390/net/Makefile b/trunk/drivers/s390/net/Makefile index 4777e36a922f..bbe3ab2e93d9 100644 --- a/trunk/drivers/s390/net/Makefile +++ b/trunk/drivers/s390/net/Makefile @@ -4,7 +4,6 @@ ctc-objs := ctcmain.o ctcdbug.o -obj-$(CONFIG_IUCV) += iucv.o obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o obj-$(CONFIG_SMSGIUCV) += smsgiucv.o obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o diff --git a/trunk/drivers/s390/net/iucv.c b/trunk/drivers/s390/net/iucv.c deleted file mode 100644 index 229aeb5fc399..000000000000 --- a/trunk/drivers/s390/net/iucv.c +++ /dev/null @@ -1,2540 +0,0 @@ -/* - * IUCV network driver - * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): - * Original source: - * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 - * Xenia Tkatschow (xenia@us.ibm.com) - * 2Gb awareness and general cleanup: - * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) - * - * Documentation used: - * The original source - * CP Programming Service, IBM document # SC24-5760 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* #define DEBUG */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iucv.h" -#include -#include -#include -#include -#include - -/* FLAGS: - * All flags are defined in the field IPFLAGS1 of each function - * and can be found in CP Programming Services. - * IPSRCCLS - Indicates you have specified a source class - * IPFGMCL - Indicates you have specified a target class - * IPFGPID - Indicates you have specified a pathid - * IPFGMID - Indicates you have specified a message ID - * IPANSLST - Indicates that you are using an address list for - * reply data - * IPBUFLST - Indicates that you are using an address list for - * message data - */ - -#define IPSRCCLS 0x01 -#define IPFGMCL 0x01 -#define IPFGPID 0x02 -#define IPFGMID 0x04 -#define IPANSLST 0x08 -#define IPBUFLST 0x40 - -static int -iucv_bus_match (struct device *dev, struct device_driver *drv) -{ - return 0; -} - -struct bus_type iucv_bus = { - .name = "iucv", - .match = iucv_bus_match, -}; - -struct device *iucv_root; - -/* General IUCV interrupt structure */ -typedef struct { - __u16 ippathid; - __u8 res1; - __u8 iptype; - __u32 res2; - __u8 ipvmid[8]; - __u8 res3[24]; -} iucv_GeneralInterrupt; - -static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL; - -/* Spin Lock declaration */ - -static DEFINE_SPINLOCK(iucv_lock); - -static int messagesDisabled = 0; - -/***************INTERRUPT HANDLING ***************/ - -typedef struct { - struct list_head queue; - iucv_GeneralInterrupt data; -} iucv_irqdata; - -static struct list_head iucv_irq_queue; -static DEFINE_SPINLOCK(iucv_irq_queue_lock); - -/* - *Internal function prototypes - */ -static void iucv_tasklet_handler(unsigned long); -static void iucv_irq_handler(__u16); - -static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0); - -/************ FUNCTION ID'S ****************************/ - -#define ACCEPT 10 -#define CONNECT 11 -#define DECLARE_BUFFER 12 -#define PURGE 9 -#define QUERY 0 -#define QUIESCE 13 -#define RECEIVE 5 -#define REJECT 8 -#define REPLY 6 -#define RESUME 14 -#define RETRIEVE_BUFFER 2 -#define SEND 4 -#define SETMASK 16 -#define SEVER 15 - -/** - * Structure: handler - * members: list - list management. - * structure: id - * userid - 8 char array of machine identification - * user_data - 16 char array for user identification - * mask - 24 char array used to compare the 2 previous - * interrupt_table - vector of interrupt functions. - * pgm_data - ulong, application data that is passed - * to the interrupt handlers -*/ -typedef struct handler_t { - struct list_head list; - struct { - __u8 userid[8]; - __u8 user_data[16]; - __u8 mask[24]; - } id; - iucv_interrupt_ops_t *interrupt_table; - void *pgm_data; -} handler; - -/** - * iucv_handler_table: List of registered handlers. - */ -static struct list_head iucv_handler_table; - -/** - * iucv_pathid_table: an array of *handler pointing into - * iucv_handler_table for fast indexing by pathid; - */ -static handler **iucv_pathid_table; - -static unsigned long max_connections; - -/** - * iucv_cpuid: contains the logical cpu number of the cpu which - * has declared the iucv buffer by issuing DECLARE_BUFFER. - * If no cpu has done the initialization iucv_cpuid contains -1. - */ -static int iucv_cpuid = -1; -/** - * register_flag: is 0 when external interrupt has not been registered - */ -static int register_flag; - -/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/ -/* Data struct 1: iparml_control - * Used for iucv_accept - * iucv_connect - * iucv_quiesce - * iucv_resume - * iucv_sever - * iucv_retrieve_buffer - * Data struct 2: iparml_dpl (data in parameter list) - * Used for iucv_send_prmmsg - * iucv_send2way_prmmsg - * iucv_send2way_prmmsg_array - * iucv_reply_prmmsg - * Data struct 3: iparml_db (data in a buffer) - * Used for iucv_receive - * iucv_receive_array - * iucv_reject - * iucv_reply - * iucv_reply_array - * iucv_send - * iucv_send_array - * iucv_send2way - * iucv_send2way_array - * iucv_declare_buffer - * Data struct 4: iparml_purge - * Used for iucv_purge - * iucv_query - * Data struct 5: iparml_set_mask - * Used for iucv_set_mask - */ - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u16 ipmsglim; - __u16 res1; - __u8 ipvmid[8]; - __u8 ipuser[16]; - __u8 iptarget[8]; -} iparml_control; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u32 iptrgcls; - __u8 iprmmsg[8]; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 ipbfadr2; - __u32 ipbfln2f; - __u32 res; -} iparml_dpl; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u32 iptrgcls; - __u32 ipbfadr1; - __u32 ipbfln1f; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 ipbfadr2; - __u32 ipbfln2f; - __u32 res; -} iparml_db; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u8 ipaudit[3]; - __u8 res1[5]; - __u32 res2; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 res3[3]; -} iparml_purge; - -typedef struct { - __u8 ipmask; - __u8 res1[2]; - __u8 iprcode; - __u32 res2[9]; -} iparml_set_mask; - -typedef struct { - union { - iparml_control p_ctrl; - iparml_dpl p_dpl; - iparml_db p_db; - iparml_purge p_purge; - iparml_set_mask p_set_mask; - } param; - atomic_t in_use; - __u32 res; -} __attribute__ ((aligned(8))) iucv_param; -#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param)) - -static iucv_param * iucv_param_pool; - -MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); -MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver"); -MODULE_LICENSE("GPL"); - -/* - * Debugging stuff - *******************************************************************************/ - - -#ifdef DEBUG -static int debuglevel = 0; - -module_param(debuglevel, int, 0); -MODULE_PARM_DESC(debuglevel, - "Specifies the debug level (0=off ... 3=all)"); - -static void -iucv_dumpit(char *title, void *buf, int len) -{ - int i; - __u8 *p = (__u8 *)buf; - - if (debuglevel < 3) - return; - - printk(KERN_DEBUG "%s\n", title); - printk(" "); - for (i = 0; i < len; i++) { - if (!(i % 16) && i != 0) - printk ("\n "); - else if (!(i % 4) && i != 0) - printk(" "); - printk("%02X", *p++); - } - if (len % 16) - printk ("\n"); - return; -} -#define iucv_debug(lvl, fmt, args...) \ -do { \ - if (debuglevel >= lvl) \ - printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \ -} while (0) - -#else - -#define iucv_debug(lvl, fmt, args...) do { } while (0) -#define iucv_dumpit(title, buf, len) do { } while (0) - -#endif - -/* - * Internal functions - *******************************************************************************/ - -/** - * print start banner - */ -static void -iucv_banner(void) -{ - printk(KERN_INFO "IUCV lowlevel driver initialized\n"); -} - -/** - * iucv_init - Initialization - * - * Allocates and initializes various data structures. - */ -static int -iucv_init(void) -{ - int ret; - - if (iucv_external_int_buffer) - return 0; - - if (!MACHINE_IS_VM) { - printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n"); - return -EPROTONOSUPPORT; - } - - ret = bus_register(&iucv_bus); - if (ret) { - printk(KERN_ERR "IUCV: failed to register bus.\n"); - return ret; - } - - iucv_root = s390_root_dev_register("iucv"); - if (IS_ERR(iucv_root)) { - printk(KERN_ERR "IUCV: failed to register iucv root.\n"); - bus_unregister(&iucv_bus); - return PTR_ERR(iucv_root); - } - - /* Note: GFP_DMA used used to get memory below 2G */ - iucv_external_int_buffer = kzalloc(sizeof(iucv_GeneralInterrupt), - GFP_KERNEL|GFP_DMA); - if (!iucv_external_int_buffer) { - printk(KERN_WARNING - "%s: Could not allocate external interrupt buffer\n", - __FUNCTION__); - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - return -ENOMEM; - } - - /* Initialize parameter pool */ - iucv_param_pool = kzalloc(sizeof(iucv_param) * PARAM_POOL_SIZE, - GFP_KERNEL|GFP_DMA); - if (!iucv_param_pool) { - printk(KERN_WARNING "%s: Could not allocate param pool\n", - __FUNCTION__); - kfree(iucv_external_int_buffer); - iucv_external_int_buffer = NULL; - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - return -ENOMEM; - } - - /* Initialize irq queue */ - INIT_LIST_HEAD(&iucv_irq_queue); - - /* Initialize handler table */ - INIT_LIST_HEAD(&iucv_handler_table); - - iucv_banner(); - return 0; -} - -/** - * iucv_exit - De-Initialization - * - * Frees everything allocated from iucv_init. - */ -static int iucv_retrieve_buffer (void); - -static void -iucv_exit(void) -{ - iucv_retrieve_buffer(); - kfree(iucv_external_int_buffer); - iucv_external_int_buffer = NULL; - kfree(iucv_param_pool); - iucv_param_pool = NULL; - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - printk(KERN_INFO "IUCV lowlevel driver unloaded\n"); -} - -/** - * grab_param: - Get a parameter buffer from the pre-allocated pool. - * - * This function searches for an unused element in the pre-allocated pool - * of parameter buffers. If one is found, it marks it "in use" and returns - * a pointer to it. The calling function is responsible for releasing it - * when it has finished its usage. - * - * Returns: A pointer to iucv_param. - */ -static __inline__ iucv_param * -grab_param(void) -{ - iucv_param *ptr; - static int hint = 0; - - ptr = iucv_param_pool + hint; - do { - ptr++; - if (ptr >= iucv_param_pool + PARAM_POOL_SIZE) - ptr = iucv_param_pool; - } while (atomic_cmpxchg(&ptr->in_use, 0, 1) != 0); - hint = ptr - iucv_param_pool; - - memset(&ptr->param, 0, sizeof(ptr->param)); - return ptr; -} - -/** - * release_param - Release a parameter buffer. - * @p: A pointer to a struct iucv_param, previously obtained by calling - * grab_param(). - * - * This function marks the specified parameter buffer "unused". - */ -static __inline__ void -release_param(void *p) -{ - atomic_set(&((iucv_param *)p)->in_use, 0); -} - -/** - * iucv_add_handler: - Add a new handler - * @new_handler: handle that is being entered into chain. - * - * Places new handle on iucv_handler_table, if identical handler is not - * found. - * - * Returns: 0 on success, !0 on failure (handler already in chain). - */ -static int -iucv_add_handler (handler *new) -{ - ulong flags; - - iucv_debug(1, "entering"); - iucv_dumpit("handler:", new, sizeof(handler)); - - spin_lock_irqsave (&iucv_lock, flags); - if (!list_empty(&iucv_handler_table)) { - struct list_head *lh; - - /** - * Search list for handler with identical id. If one - * is found, the new handler is _not_ added. - */ - list_for_each(lh, &iucv_handler_table) { - handler *h = list_entry(lh, handler, list); - if (!memcmp(&new->id, &h->id, sizeof(h->id))) { - iucv_debug(1, "ret 1"); - spin_unlock_irqrestore (&iucv_lock, flags); - return 1; - } - } - } - /** - * If we get here, no handler was found. - */ - INIT_LIST_HEAD(&new->list); - list_add(&new->list, &iucv_handler_table); - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_debug(1, "exiting"); - return 0; -} - -/** - * b2f0: - * @code: identifier of IUCV call to CP. - * @parm: pointer to 40 byte iparml area passed to CP - * - * Calls CP to execute IUCV commands. - * - * Returns: return code from CP's IUCV call - */ -static inline ulong b2f0(__u32 code, void *parm) -{ - register unsigned long reg0 asm ("0"); - register unsigned long reg1 asm ("1"); - iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param)); - - reg0 = code; - reg1 = virt_to_phys(parm); - asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1)); - - iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param)); - - return (unsigned long)*((__u8 *)(parm + 3)); -} - -/* - * Name: iucv_add_pathid - * Purpose: Adds a path id to the system. - * Input: pathid - pathid that is going to be entered into system - * handle - address of handler that the pathid will be associated - * with. - * pgm_data - token passed in by application. - * Output: 0: successful addition of pathid - * - EINVAL - pathid entry is being used by another application - * - ENOMEM - storage allocation for a new pathid table failed -*/ -static int -__iucv_add_pathid(__u16 pathid, handler *handler) -{ - - iucv_debug(1, "entering"); - - iucv_debug(1, "handler is pointing to %p", handler); - - if (pathid > (max_connections - 1)) - return -EINVAL; - - if (iucv_pathid_table[pathid]) { - iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]); - printk(KERN_WARNING - "%s: Pathid being used, error.\n", __FUNCTION__); - return -EINVAL; - } - iucv_pathid_table[pathid] = handler; - - iucv_debug(1, "exiting"); - return 0; -} /* end of add_pathid function */ - -static int -iucv_add_pathid(__u16 pathid, handler *handler) -{ - ulong flags; - int rc; - - spin_lock_irqsave (&iucv_lock, flags); - rc = __iucv_add_pathid(pathid, handler); - spin_unlock_irqrestore (&iucv_lock, flags); - return rc; -} - -static void -iucv_remove_pathid(__u16 pathid) -{ - ulong flags; - - if (pathid > (max_connections - 1)) - return; - - spin_lock_irqsave (&iucv_lock, flags); - iucv_pathid_table[pathid] = NULL; - spin_unlock_irqrestore (&iucv_lock, flags); -} - -/** - * iucv_declare_buffer_cpuid - * Register at VM for subsequent IUCV operations. This is executed - * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer(). - */ -static void -iucv_declare_buffer_cpuid (void *result) -{ - iparml_db *parm; - - parm = (iparml_db *)grab_param(); - parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer); - if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1) - *((ulong *)result) = parm->iprcode; - release_param(parm); -} - -/** - * iucv_retrieve_buffer_cpuid: - * Unregister IUCV usage at VM. This is always executed on the same - * cpu that registered the buffer to VM. - * Called from iucv_retrieve_buffer(). - */ -static void -iucv_retrieve_buffer_cpuid (void *cpu) -{ - iparml_control *parm; - - parm = (iparml_control *)grab_param(); - b2f0(RETRIEVE_BUFFER, parm); - release_param(parm); -} - -/** - * Name: iucv_declare_buffer - * Purpose: Specifies the guests real address of an external - * interrupt. - * Input: void - * Output: iprcode - return code from b2f0 call - */ -static int -iucv_declare_buffer (void) -{ - unsigned long flags; - ulong b2f0_result; - - iucv_debug(1, "entering"); - b2f0_result = -ENODEV; - spin_lock_irqsave (&iucv_lock, flags); - if (iucv_cpuid == -1) { - /* Reserve any cpu for use by iucv. */ - iucv_cpuid = smp_get_cpu(CPU_MASK_ALL); - spin_unlock_irqrestore (&iucv_lock, flags); - smp_call_function_on(iucv_declare_buffer_cpuid, - &b2f0_result, 0, 1, iucv_cpuid); - if (b2f0_result) { - smp_put_cpu(iucv_cpuid); - iucv_cpuid = -1; - } - iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer); - } else { - spin_unlock_irqrestore (&iucv_lock, flags); - b2f0_result = 0; - } - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_retrieve_buffer: - * - * Terminates all use of IUCV. - * Returns: return code from CP - */ -static int -iucv_retrieve_buffer (void) -{ - iucv_debug(1, "entering"); - if (iucv_cpuid != -1) { - smp_call_function_on(iucv_retrieve_buffer_cpuid, - NULL, 0, 1, iucv_cpuid); - /* Release the cpu reserved by iucv_declare_buffer. */ - smp_put_cpu(iucv_cpuid); - iucv_cpuid = -1; - } - iucv_debug(1, "exiting"); - return 0; -} - -/** - * iucv_remove_handler: - * @users_handler: handler to be removed - * - * Remove handler when application unregisters. - */ -static void -iucv_remove_handler(handler *handler) -{ - unsigned long flags; - - if ((!iucv_pathid_table) || (!handler)) - return; - - iucv_debug(1, "entering"); - - spin_lock_irqsave (&iucv_lock, flags); - list_del(&handler->list); - if (list_empty(&iucv_handler_table)) { - if (register_flag) { - unregister_external_interrupt(0x4000, iucv_irq_handler); - register_flag = 0; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_debug(1, "exiting"); - return; -} - -/** - * iucv_register_program: - * @pgmname: user identification - * @userid: machine identification - * @pgmmask: Indicates which bits in the pgmname and userid combined will be - * used to determine who is given control. - * @ops: Address of interrupt handler table. - * @pgm_data: Application data to be passed to interrupt handlers. - * - * Registers an application with IUCV. - * Returns: - * The address of handler, or NULL on failure. - * NOTE on pgmmask: - * If pgmname, userid and pgmmask are provided, pgmmask is entered into the - * handler as is. - * If pgmmask is NULL, the internal mask is set to all 0xff's - * When userid is NULL, the first 8 bytes of the internal mask are forced - * to 0x00. - * If pgmmask and userid are NULL, the first 8 bytes of the internal mask - * are forced to 0x00 and the last 16 bytes to 0xff. - */ - -iucv_handle_t -iucv_register_program (__u8 pgmname[16], - __u8 userid[8], - __u8 pgmmask[24], - iucv_interrupt_ops_t * ops, void *pgm_data) -{ - ulong rc = 0; /* return code from function calls */ - handler *new_handler; - - iucv_debug(1, "entering"); - - if (ops == NULL) { - /* interrupt table is not defined */ - printk(KERN_WARNING "%s: Interrupt table is not defined, " - "exiting\n", __FUNCTION__); - return NULL; - } - if (!pgmname) { - printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__); - return NULL; - } - - /* Allocate handler entry */ - new_handler = kmalloc(sizeof(handler), GFP_ATOMIC); - if (new_handler == NULL) { - printk(KERN_WARNING "%s: storage allocation for new handler " - "failed.\n", __FUNCTION__); - return NULL; - } - - if (!iucv_pathid_table) { - if (iucv_init()) { - kfree(new_handler); - return NULL; - } - - max_connections = iucv_query_maxconn(); - iucv_pathid_table = kcalloc(max_connections, sizeof(handler *), - GFP_ATOMIC); - if (iucv_pathid_table == NULL) { - printk(KERN_WARNING "%s: iucv_pathid_table storage " - "allocation failed\n", __FUNCTION__); - kfree(new_handler); - return NULL; - } - } - memset(new_handler, 0, sizeof (handler)); - memcpy(new_handler->id.user_data, pgmname, - sizeof (new_handler->id.user_data)); - if (userid) { - memcpy (new_handler->id.userid, userid, - sizeof (new_handler->id.userid)); - ASCEBC (new_handler->id.userid, - sizeof (new_handler->id.userid)); - EBC_TOUPPER (new_handler->id.userid, - sizeof (new_handler->id.userid)); - - if (pgmmask) { - memcpy (new_handler->id.mask, pgmmask, - sizeof (new_handler->id.mask)); - } else { - memset (new_handler->id.mask, 0xFF, - sizeof (new_handler->id.mask)); - } - } else { - if (pgmmask) { - memcpy (new_handler->id.mask, pgmmask, - sizeof (new_handler->id.mask)); - } else { - memset (new_handler->id.mask, 0xFF, - sizeof (new_handler->id.mask)); - } - memset (new_handler->id.userid, 0x00, - sizeof (new_handler->id.userid)); - } - /* fill in the rest of handler */ - new_handler->pgm_data = pgm_data; - new_handler->interrupt_table = ops; - - /* - * Check if someone else is registered with same pgmname, userid - * and mask. If someone is already registered with same pgmname, - * userid and mask, registration will fail and NULL will be returned - * to the application. - * If identical handler not found, then handler is added to list. - */ - rc = iucv_add_handler(new_handler); - if (rc) { - printk(KERN_WARNING "%s: Someone already registered with same " - "pgmname, userid, pgmmask\n", __FUNCTION__); - kfree (new_handler); - return NULL; - } - - rc = iucv_declare_buffer(); - if (rc) { - char *err = "Unknown"; - iucv_remove_handler(new_handler); - kfree(new_handler); - switch(rc) { - case 0x03: - err = "Directory error"; - break; - case 0x0a: - err = "Invalid length"; - break; - case 0x13: - err = "Buffer already exists"; - break; - case 0x3e: - err = "Buffer overlap"; - break; - case 0x5c: - err = "Paging or storage error"; - break; - } - printk(KERN_WARNING "%s: iucv_declare_buffer " - "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err); - return NULL; - } - if (!register_flag) { - /* request the 0x4000 external interrupt */ - rc = register_external_interrupt (0x4000, iucv_irq_handler); - if (rc) { - iucv_remove_handler(new_handler); - kfree (new_handler); - printk(KERN_WARNING "%s: " - "register_external_interrupt returned %ld\n", - __FUNCTION__, rc); - return NULL; - - } - register_flag = 1; - } - iucv_debug(1, "exiting"); - return new_handler; -} /* end of register function */ - -/** - * iucv_unregister_program: - * @handle: address of handler - * - * Unregister application with IUCV. - * Returns: - * 0 on success, -EINVAL, if specified handle is invalid. - */ - -int -iucv_unregister_program (iucv_handle_t handle) -{ - handler *h = NULL; - struct list_head *lh; - int i; - ulong flags; - - iucv_debug(1, "entering"); - iucv_debug(1, "address of handler is %p", h); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - if (!h) { - spin_unlock_irqrestore (&iucv_lock, flags); - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - /** - * First, walk thru iucv_pathid_table and sever any pathid which is - * still pointing to the handler to be removed. - */ - for (i = 0; i < max_connections; i++) - if (iucv_pathid_table[i] == h) { - spin_unlock_irqrestore (&iucv_lock, flags); - iucv_sever(i, h->id.user_data); - spin_lock_irqsave(&iucv_lock, flags); - } - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_remove_handler(h); - kfree(h); - - iucv_debug(1, "exiting"); - return 0; -} - -/** - * iucv_accept: - * @pathid: Path identification number - * @msglim_reqstd: The number of outstanding messages requested. - * @user_data: Data specified by the iucv_connect function. - * @flags1: Contains options for this path. - * - IPPRTY (0x20) Specifies if you want to send priority message. - * - IPRMDATA (0x80) Specifies whether your program can handle a message - * in the parameter list. - * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being - * established. - * @handle: Address of handler. - * @pgm_data: Application data passed to interrupt handlers. - * @flags1_out: Pointer to an int. If not NULL, on return the options for - * the path are stored at the given location: - * - IPPRTY (0x20) Indicates you may send a priority message. - * @msglim: Pointer to an __u16. If not NULL, on return the maximum - * number of outstanding messages is stored at the given - * location. - * - * This function is issued after the user receives a Connection Pending external - * interrupt and now wishes to complete the IUCV communication path. - * Returns: - * return code from CP - */ -int -iucv_accept(__u16 pathid, __u16 msglim_reqstd, - __u8 user_data[16], int flags1, - iucv_handle_t handle, void *pgm_data, - int *flags1_out, __u16 * msglim) -{ - ulong b2f0_result = 0; - ulong flags; - struct list_head *lh; - handler *h = NULL; - iparml_control *parm; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - if (!h) { - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - parm = (iparml_control *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsglim = msglim_reqstd; - if (user_data) - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - - parm->ipflags1 = (__u8)flags1; - b2f0_result = b2f0(ACCEPT, parm); - - if (!b2f0_result) { - if (msglim) - *msglim = parm->ipmsglim; - if (pgm_data) - h->pgm_data = pgm_data; - if (flags1_out) - *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; - } - release_param(parm); - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_connect: - * @pathid: Path identification number - * @msglim_reqstd: Number of outstanding messages requested - * @user_data: 16-byte user data - * @userid: 8-byte of user identification - * @system_name: 8-byte identifying the system name - * @flags1: Specifies options for this path: - * - IPPRTY (0x20) Specifies if you want to send priority message. - * - IPRMDATA (0x80) Specifies whether your program can handle a message - * in the parameter list. - * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being - * established. - * - IPLOCAL (0x01) Allows an application to force the partner to be on the - * local system. If local is specified then target class - * cannot be specified. - * @flags1_out: Pointer to an int. If not NULL, on return the options for - * the path are stored at the given location: - * - IPPRTY (0x20) Indicates you may send a priority message. - * @msglim: Pointer to an __u16. If not NULL, on return the maximum - * number of outstanding messages is stored at the given - * location. - * @handle: Address of handler. - * @pgm_data: Application data to be passed to interrupt handlers. - * - * This function establishes an IUCV path. Although the connect may complete - * successfully, you are not able to use the path until you receive an IUCV - * Connection Complete external interrupt. - * Returns: return code from CP, or one of the following - * - ENOMEM - * - return code from iucv_declare_buffer - * - EINVAL - invalid handle passed by application - * - EINVAL - pathid address is NULL - * - ENOMEM - pathid table storage allocation failed - * - return code from internal function add_pathid - */ -int -iucv_connect (__u16 *pathid, __u16 msglim_reqstd, - __u8 user_data[16], __u8 userid[8], - __u8 system_name[8], int flags1, - int *flags1_out, __u16 * msglim, - iucv_handle_t handle, void *pgm_data) -{ - iparml_control *parm; - iparml_control local_parm; - struct list_head *lh; - ulong b2f0_result = 0; - ulong flags; - int add_pathid_result = 0; - handler *h = NULL; - __u8 no_memory[16] = "NO MEMORY"; - - iucv_debug(1, "entering"); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - if (!h) { - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - if (pathid == NULL) { - printk(KERN_WARNING "%s: NULL pathid pointer\n", - __FUNCTION__); - return -EINVAL; - } - - parm = (iparml_control *)grab_param(); - - parm->ipmsglim = msglim_reqstd; - - if (user_data) - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - - if (userid) { - memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid)); - ASCEBC(parm->ipvmid, sizeof(parm->ipvmid)); - EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid)); - } - - if (system_name) { - memcpy(parm->iptarget, system_name, sizeof(parm->iptarget)); - ASCEBC(parm->iptarget, sizeof(parm->iptarget)); - EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget)); - } - - /* In order to establish an IUCV connection, the procedure is: - * - * b2f0(CONNECT) - * take the ippathid from the b2f0 call - * register the handler to the ippathid - * - * Unfortunately, the ConnectionEstablished message gets sent after the - * b2f0(CONNECT) call but before the register is handled. - * - * In order for this race condition to be eliminated, the IUCV Control - * Interrupts must be disabled for the above procedure. - * - * David Kennedy - */ - - /* Enable everything but IUCV Control messages */ - iucv_setmask(~(AllInterrupts)); - messagesDisabled = 1; - - spin_lock_irqsave (&iucv_lock, flags); - parm->ipflags1 = (__u8)flags1; - b2f0_result = b2f0(CONNECT, parm); - memcpy(&local_parm, parm, sizeof(local_parm)); - release_param(parm); - parm = &local_parm; - if (!b2f0_result) - add_pathid_result = __iucv_add_pathid(parm->ippathid, h); - spin_unlock_irqrestore (&iucv_lock, flags); - - if (b2f0_result) { - iucv_setmask(~0); - messagesDisabled = 0; - return b2f0_result; - } - - *pathid = parm->ippathid; - - /* Enable everything again */ - iucv_setmask(IUCVControlInterruptsFlag); - - if (msglim) - *msglim = parm->ipmsglim; - if (flags1_out) - *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; - - if (add_pathid_result) { - iucv_sever(*pathid, no_memory); - printk(KERN_WARNING "%s: add_pathid failed with rc =" - " %d\n", __FUNCTION__, add_pathid_result); - return(add_pathid_result); - } - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_purge: - * @pathid: Path identification number - * @msgid: Message ID of message to purge. - * @srccls: Message class of the message to purge. - * @audit: Pointer to an __u32. If not NULL, on return, information about - * asynchronous errors that may have affected the normal completion - * of this message ist stored at the given location. - * - * Cancels a message you have sent. - * Returns: return code from CP - */ -int -iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit) -{ - iparml_purge *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_purge *)grab_param(); - - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->ipsrccls = srccls; - parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID); - b2f0_result = b2f0(PURGE, parm); - - if (!b2f0_result && audit) { - memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit)); - /* parm->ipaudit has only 3 bytes */ - *audit >>= 8; - } - - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_query_generic: - * @want_maxconn: Flag, describing which value is to be returned. - * - * Helper function for iucv_query_maxconn() and iucv_query_bufsize(). - * - * Returns: The buffersize, if want_maxconn is 0; the maximum number of - * connections, if want_maxconn is 1 or an error-code < 0 on failure. - */ -static int -iucv_query_generic(int want_maxconn) -{ - register unsigned long reg0 asm ("0"); - register unsigned long reg1 asm ("1"); - iparml_purge *parm = (iparml_purge *)grab_param(); - int bufsize, maxconn; - int ccode; - - /** - * Call b2f0 and store R0 (max buffer size), - * R1 (max connections) and CC. - */ - reg0 = QUERY; - reg1 = virt_to_phys(parm); - asm volatile( - " .long 0xb2f01000\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc"); - bufsize = reg0; - maxconn = reg1; - release_param(parm); - - if (ccode) - return -EPERM; - if (want_maxconn) - return maxconn; - return bufsize; -} - -/** - * iucv_query_maxconn: - * - * Determines the maximum number of connections thay may be established. - * - * Returns: Maximum number of connections that can be. - */ -ulong -iucv_query_maxconn(void) -{ - return iucv_query_generic(1); -} - -/** - * iucv_query_bufsize: - * - * Determines the size of the external interrupt buffer. - * - * Returns: Size of external interrupt buffer. - */ -ulong -iucv_query_bufsize (void) -{ - return iucv_query_generic(0); -} - -/** - * iucv_quiesce: - * @pathid: Path identification number - * @user_data: 16-byte user data - * - * Temporarily suspends incoming messages on an IUCV path. - * You can later reactivate the path by invoking the iucv_resume function. - * Returns: return code from CP - */ -int -iucv_quiesce (__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_control *)grab_param(); - - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - parm->ippathid = pathid; - - b2f0_result = b2f0(QUIESCE, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/** - * iucv_receive: - * @pathid: Path identification number. - * @buffer: Address of buffer to receive. Must be below 2G. - * @buflen: Length of buffer to receive. - * @msgid: Specifies the message ID. - * @trgcls: Specifies target class. - * @flags1_out: Receives options for path on return. - * - IPNORPY (0x10) Specifies whether a reply is required - * - IPPRTY (0x20) Specifies if you want to send priority message - * - IPRMDATA (0x80) Specifies the data is contained in the parameter list - * @residual_buffer: Receives the address of buffer updated by the number - * of bytes you have received on return. - * @residual_length: On return, receives one of the following values: - * - 0 If the receive buffer is the same length as - * the message. - * - Remaining bytes in buffer If the receive buffer is longer than the - * message. - * - Remaining bytes in message If the receive buffer is shorter than the - * message. - * - * This function receives messages that are being sent to you over established - * paths. - * Returns: return code from CP IUCV call; If the receive buffer is shorter - * than the message, always 5 - * -EINVAL - buffer address is pointing to NULL - */ -int -iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls, - void *buffer, ulong buflen, - int *flags1_out, ulong * residual_buffer, ulong * residual_length) -{ - iparml_db *parm; - ulong b2f0_result; - int moved = 0; /* number of bytes moved from parmlist to buffer */ - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) (addr_t) buffer; - parm->ipbfln1f = (__u32) ((ulong) buflen); - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL); - - b2f0_result = b2f0(RECEIVE, parm); - - if (!b2f0_result || b2f0_result == 5) { - if (flags1_out) { - iucv_debug(2, "*flags1_out = %d", *flags1_out); - *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug(2, "*flags1_out = %d", *flags1_out); - } - - if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ - if (residual_length) - *residual_length = parm->ipbfln1f; - - if (residual_buffer) - *residual_buffer = parm->ipbfadr1; - } else { - moved = min_t (unsigned long, buflen, 8); - - memcpy ((char *) buffer, - (char *) &parm->ipbfadr1, moved); - - if (buflen < 8) - b2f0_result = 5; - - if (residual_length) - *residual_length = abs (buflen - 8); - - if (residual_buffer) - *residual_buffer = (ulong) (buffer + moved); - } - } - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_receive_array - * Purpose: This function receives messages that are being sent to you - * over established paths. - * Input: pathid - path identification number - * buffer - address of array of buffers - * buflen - total length of buffers - * msgid - specifies the message ID. - * trgcls - specifies target class - * Output: - * flags1_out: Options for path. - * IPNORPY - 0x10 specifies whether a reply is required - * IPPRTY - 0x20 specifies if you want to send priority message - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address points to the current list entry IUCV - * is working on. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this case - * b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_receive_array (__u16 pathid, - __u32 msgid, __u32 trgcls, - iucv_array_t * buffer, ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length) -{ - iparml_db *parm; - ulong b2f0_result; - int i = 0, moved = 0, need_to_move = 8, dyn_len; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL); - - b2f0_result = b2f0(RECEIVE, parm); - - if (!b2f0_result || b2f0_result == 5) { - - if (flags1_out) { - iucv_debug(2, "*flags1_out = %d", *flags1_out); - *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug(2, "*flags1_out = %d", *flags1_out); - } - - if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ - - if (residual_length) - *residual_length = parm->ipbfln1f; - - if (residual_buffer) - *residual_buffer = parm->ipbfadr1; - - } else { - /* copy msg from parmlist to users array. */ - - while ((moved < 8) && (moved < buflen)) { - dyn_len = - min_t (unsigned int, - (buffer + i)->length, need_to_move); - - memcpy ((char *)((ulong)((buffer + i)->address)), - ((char *) &parm->ipbfadr1) + moved, - dyn_len); - - moved += dyn_len; - need_to_move -= dyn_len; - - (buffer + i)->address = - (__u32) - ((ulong)(__u8 *) ((ulong)(buffer + i)->address) - + dyn_len); - - (buffer + i)->length -= dyn_len; - i++; - } - - if (need_to_move) /* buflen < 8 bytes */ - b2f0_result = 5; - - if (residual_length) - *residual_length = abs (buflen - 8); - - if (residual_buffer) { - if (!moved) - *residual_buffer = (ulong) buffer; - else - *residual_buffer = - (ulong) (buffer + (i - 1)); - } - - } - } - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/** - * iucv_reject: - * @pathid: Path identification number. - * @msgid: Message ID of the message to reject. - * @trgcls: Target class of the message to reject. - * Returns: return code from CP - * - * Refuses a specified message. Between the time you are notified of a - * message and the time that you complete the message, the message may - * be rejected. - */ -int -iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls) -{ - iparml_db *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID); - - b2f0_result = b2f0(REJECT, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- 0x20 - specifies if you want to send priority message - * buffer - address of reply buffer - * buflen - length of reply buffer - * Output: ipbfadr2 - Address of buffer updated by the number - * of bytes you have moved. - * ipbfln2f - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_reply (__u16 pathid, - __u32 msgid, __u32 trgcls, - int flags1, - void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr2 = (__u32) ((ulong) buffer); - parm->ipbfln2f = (__u32) buflen; /* length of message */ - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (__u8) flags1; /* priority message */ - - b2f0_result = b2f0(REPLY, parm); - - if ((!b2f0_result) || (b2f0_result == 5)) { - if (ipbfadr2) - *ipbfadr2 = parm->ipbfadr2; - if (ipbfln2f) - *ipbfln2f = parm->ipbfln2f; - } - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply_array - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * The array identifies a list of addresses and lengths of - * discontiguous buffers that contains the reply data. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of reply buffers - * buflen - total length of reply buffers - * Output: ipbfadr2 - Address of buffer which IUCV is currently working on. - * ipbfln2f - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL -*/ -int -iucv_reply_array (__u16 pathid, - __u32 msgid, __u32 trgcls, - int flags1, - iucv_array_t * buffer, - ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr2 = (__u32) ((ulong) buffer); - parm->ipbfln2f = buflen; /* length of message */ - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPANSLST | flags1); - - b2f0_result = b2f0(REPLY, parm); - - if ((!b2f0_result) || (b2f0_result == 5)) { - - if (ipbfadr2) - *ipbfadr2 = parm->ipbfadr2; - if (ipbfln2f) - *ipbfln2f = parm->ipbfln2f; - } - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply_prmmsg - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Prmmsg signifies the data is moved into the - * parameter list. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into the parameter - * list. - * Output: NA - * Return: b2f0_result - return code from CP -*/ -int -iucv_reply_prmmsg (__u16 pathid, - __u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8]) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg)); - parm->ipflags1 = (IPRMDATA | flags1); - - b2f0_result = b2f0(REPLY, parm); - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/** - * iucv_resume: - * @pathid: Path identification number - * @user_data: 16-byte of user data - * - * This function restores communication over a quiesced path. - * Returns: return code from CP - */ -int -iucv_resume (__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_control *)grab_param(); - - memcpy (parm->ipuser, user_data, sizeof (*user_data)); - parm->ippathid = pathid; - - b2f0_result = b2f0(RESUME, parm); - release_param(parm); - - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send - * Purpose: sends messages - * Input: pathid - ushort, pathid - * msgid - ulong *, id of message returned to caller - * trgcls - ulong, target message class - * srccls - ulong, source message class - * msgtag - ulong, message tag - * flags1 - Contains options for this path. - * IPPRTY - Ox20 - specifies if you want to send a priority message. - * buffer - pointer to buffer - * buflen - ulong, length of buffer - * Output: b2f0_result - return code from b2f0 call - * msgid - returns message id - */ -int -iucv_send (__u16 pathid, __u32 * msgid, - __u32 trgcls, __u32 srccls, - __u32 msgtag, int flags1, void *buffer, ulong buflen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPNORPY | flags1); /* one way priority message */ - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated witht the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of send buffers - * buflen - total length of send buffers - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_send_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPNORPY | IPBUFLST | flags1); - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_send_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into parameter list - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP -*/ -int -iucv_send_prmmsg (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8]) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPRMDATA | IPNORPY | flags1); - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer. The receiver - * of the send is expected to reply to the message and - * a buffer is provided into which IUCV moves the reply - * to this message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of send buffer - * buflen - length of send buffer - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer or ansbuf address is NULL - */ -int -iucv_send2way (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - void *buffer, ulong buflen, void *ansbuf, ulong anslen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer || !ansbuf) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = flags1; /* priority message */ - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. The receiver of the send is expected to - * reply to the message and a buffer is provided into which - * IUCV moves the reply to this message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - spcifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of send buffers - * buflen - total length of send buffers - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_send2way_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - iucv_array_t * buffer, - ulong buflen, iucv_array_t * ansbuf, ulong anslen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer || !ansbuf) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPBUFLST | IPANSLST | flags1); - b2f0_result = b2f0(SEND, parm); - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_send2way_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed in parameter list - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL -*/ -int -iucv_send2way_prmmsg (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!ansbuf) - return -EINVAL; - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipflags1 = (IPRMDATA | flags1); /* message in prmlist */ - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way_prmmsg_array - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. The contents of ansbuf is the address of the - * array of addresses and lengths of discontiguous buffers - * that contain the reply. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into the parameter list - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - ansbuf address is NULL - */ -int -iucv_send2way_prmmsg_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - __u8 prmmsg[8], - iucv_array_t * ansbuf, ulong anslen) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!ansbuf) - return -EINVAL; - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipflags1 = (IPRMDATA | IPANSLST | flags1); - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - b2f0_result = b2f0(SEND, parm); - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -void -iucv_setmask_cpuid (void *result) -{ - iparml_set_mask *parm; - - iucv_debug(1, "entering"); - parm = (iparml_set_mask *)grab_param(); - parm->ipmask = *((__u8*)result); - *((ulong *)result) = b2f0(SETMASK, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", *((ulong *)result)); - iucv_debug(1, "exiting"); -} - -/* - * Name: iucv_setmask - * Purpose: This function enables or disables the following IUCV - * external interruptions: Nonpriority and priority message - * interrupts, nonpriority and priority reply interrupts. - * Input: SetMaskFlag - options for interrupts - * 0x80 - Nonpriority_MessagePendingInterruptsFlag - * 0x40 - Priority_MessagePendingInterruptsFlag - * 0x20 - Nonpriority_MessageCompletionInterruptsFlag - * 0x10 - Priority_MessageCompletionInterruptsFlag - * 0x08 - IUCVControlInterruptsFlag - * Output: NA - * Return: b2f0_result - return code from CP -*/ -int -iucv_setmask (int SetMaskFlag) -{ - union { - ulong result; - __u8 param; - } u; - int cpu; - - u.param = SetMaskFlag; - cpu = get_cpu(); - smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid); - put_cpu(); - - return u.result; -} - -/** - * iucv_sever: - * @pathid: Path identification number - * @user_data: 16-byte of user data - * - * This function terminates an iucv path. - * Returns: return code from CP - */ -int -iucv_sever(__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - parm = (iparml_control *)grab_param(); - - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - parm->ippathid = pathid; - - b2f0_result = b2f0(SEVER, parm); - - if (!b2f0_result) - iucv_remove_pathid(pathid); - release_param(parm); - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/* - * Interrupt Handlers - *******************************************************************************/ - -/** - * iucv_irq_handler: - * @regs: Current registers - * @code: irq code - * - * Handles external interrupts coming in from CP. - * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler(). - */ -static void -iucv_irq_handler(__u16 code) -{ - iucv_irqdata *irqdata; - - irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC); - if (!irqdata) { - printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__); - return; - } - - memcpy(&irqdata->data, iucv_external_int_buffer, - sizeof(iucv_GeneralInterrupt)); - - spin_lock(&iucv_irq_queue_lock); - list_add_tail(&irqdata->queue, &iucv_irq_queue); - spin_unlock(&iucv_irq_queue_lock); - - tasklet_schedule(&iucv_tasklet); -} - -/** - * iucv_do_int: - * @int_buf: Pointer to copy of external interrupt buffer - * - * The workhorse for handling interrupts queued by iucv_irq_handler(). - * This function is called from the bottom half iucv_tasklet_handler(). - */ -static void -iucv_do_int(iucv_GeneralInterrupt * int_buf) -{ - handler *h = NULL; - struct list_head *lh; - ulong flags; - iucv_interrupt_ops_t *interrupt = NULL; /* interrupt addresses */ - __u8 temp_buff1[24], temp_buff2[24]; /* masked handler id. */ - int rc = 0, j = 0; - __u8 no_listener[16] = "NO LISTENER"; - - iucv_debug(2, "entering, pathid %d, type %02X", - int_buf->ippathid, int_buf->iptype); - iucv_dumpit("External Interrupt Buffer:", - int_buf, sizeof(iucv_GeneralInterrupt)); - - ASCEBC (no_listener, 16); - - if (int_buf->iptype != 01) { - if ((int_buf->ippathid) > (max_connections - 1)) { - printk(KERN_WARNING "%s: Got interrupt with pathid %d" - " > max_connections (%ld)\n", __FUNCTION__, - int_buf->ippathid, max_connections - 1); - } else { - h = iucv_pathid_table[int_buf->ippathid]; - interrupt = h->interrupt_table; - iucv_dumpit("Handler:", h, sizeof(handler)); - } - } - - /* end of if statement */ - switch (int_buf->iptype) { - case 0x01: /* connection pending */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - spin_lock_irqsave(&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - h = list_entry(lh, handler, list); - memcpy(temp_buff1, &(int_buf->ipvmid), 24); - memcpy(temp_buff2, &(h->id.userid), 24); - for (j = 0; j < 24; j++) { - temp_buff1[j] &= (h->id.mask)[j]; - temp_buff2[j] &= (h->id.mask)[j]; - } - - iucv_dumpit("temp_buff1:", - temp_buff1, sizeof(temp_buff1)); - iucv_dumpit("temp_buff2", - temp_buff2, sizeof(temp_buff2)); - - if (!memcmp (temp_buff1, temp_buff2, 24)) { - - iucv_debug(2, - "found a matching handler"); - break; - } else - h = NULL; - } - spin_unlock_irqrestore (&iucv_lock, flags); - if (h) { - /* ADD PATH TO PATHID TABLE */ - rc = iucv_add_pathid(int_buf->ippathid, h); - if (rc) { - iucv_sever (int_buf->ippathid, - no_listener); - iucv_debug(1, - "add_pathid failed, rc = %d", - rc); - } else { - interrupt = h->interrupt_table; - if (interrupt->ConnectionPending) { - EBCASC (int_buf->ipvmid, 8); - interrupt->ConnectionPending( - (iucv_ConnectionPending *)int_buf, - h->pgm_data); - } else - iucv_sever(int_buf->ippathid, - no_listener); - } - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x02: /*connection complete */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionComplete) - { - interrupt->ConnectionComplete( - (iucv_ConnectionComplete *)int_buf, - h->pgm_data); - } - else - iucv_debug(1, - "ConnectionComplete not called"); - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x03: /* connection severed */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionSevered) - interrupt->ConnectionSevered( - (iucv_ConnectionSevered *)int_buf, - h->pgm_data); - - else - iucv_sever (int_buf->ippathid, no_listener); - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x04: /* connection quiesced */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionQuiesced) - interrupt->ConnectionQuiesced( - (iucv_ConnectionQuiesced *)int_buf, - h->pgm_data); - else - iucv_debug(1, - "ConnectionQuiesced not called"); - } - break; - - case 0x05: /* connection resumed */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionResumed) - interrupt->ConnectionResumed( - (iucv_ConnectionResumed *)int_buf, - h->pgm_data); - else - iucv_debug(1, - "ConnectionResumed not called"); - } - break; - - case 0x06: /* priority message complete */ - case 0x07: /* nonpriority message complete */ - if (h) { - if (interrupt->MessageComplete) - interrupt->MessageComplete( - (iucv_MessageComplete *)int_buf, - h->pgm_data); - else - iucv_debug(2, - "MessageComplete not called"); - } - break; - - case 0x08: /* priority message pending */ - case 0x09: /* nonpriority message pending */ - if (h) { - if (interrupt->MessagePending) - interrupt->MessagePending( - (iucv_MessagePending *) int_buf, - h->pgm_data); - else - iucv_debug(2, - "MessagePending not called"); - } - break; - default: /* unknown iucv type */ - printk(KERN_WARNING "%s: unknown iucv interrupt\n", - __FUNCTION__); - break; - } /* end switch */ - - iucv_debug(2, "exiting pathid %d, type %02X", - int_buf->ippathid, int_buf->iptype); - - return; -} - -/** - * iucv_tasklet_handler: - * - * This function loops over the queue of irq buffers and runs iucv_do_int() - * on every queue element. - */ -static void -iucv_tasklet_handler(unsigned long ignored) -{ - struct list_head head; - struct list_head *next; - ulong flags; - - spin_lock_irqsave(&iucv_irq_queue_lock, flags); - list_add(&head, &iucv_irq_queue); - list_del_init(&iucv_irq_queue); - spin_unlock_irqrestore (&iucv_irq_queue_lock, flags); - - next = head.next; - while (next != &head) { - iucv_irqdata *p = list_entry(next, iucv_irqdata, queue); - - next = next->next; - iucv_do_int(&p->data); - kfree(p); - } - - return; -} - -subsys_initcall(iucv_init); -module_exit(iucv_exit); - -/** - * Export all public stuff - */ -EXPORT_SYMBOL (iucv_bus); -EXPORT_SYMBOL (iucv_root); -EXPORT_SYMBOL (iucv_accept); -EXPORT_SYMBOL (iucv_connect); -#if 0 -EXPORT_SYMBOL (iucv_purge); -EXPORT_SYMBOL (iucv_query_maxconn); -EXPORT_SYMBOL (iucv_query_bufsize); -EXPORT_SYMBOL (iucv_quiesce); -#endif -EXPORT_SYMBOL (iucv_receive); -#if 0 -EXPORT_SYMBOL (iucv_receive_array); -#endif -EXPORT_SYMBOL (iucv_reject); -#if 0 -EXPORT_SYMBOL (iucv_reply); -EXPORT_SYMBOL (iucv_reply_array); -EXPORT_SYMBOL (iucv_resume); -#endif -EXPORT_SYMBOL (iucv_reply_prmmsg); -EXPORT_SYMBOL (iucv_send); -EXPORT_SYMBOL (iucv_send2way); -EXPORT_SYMBOL (iucv_send2way_array); -EXPORT_SYMBOL (iucv_send2way_prmmsg); -EXPORT_SYMBOL (iucv_send2way_prmmsg_array); -#if 0 -EXPORT_SYMBOL (iucv_send_array); -EXPORT_SYMBOL (iucv_send_prmmsg); -EXPORT_SYMBOL (iucv_setmask); -#endif -EXPORT_SYMBOL (iucv_sever); -EXPORT_SYMBOL (iucv_register_program); -EXPORT_SYMBOL (iucv_unregister_program); diff --git a/trunk/drivers/s390/net/iucv.h b/trunk/drivers/s390/net/iucv.h deleted file mode 100644 index 5b6b1b7241c9..000000000000 --- a/trunk/drivers/s390/net/iucv.h +++ /dev/null @@ -1,849 +0,0 @@ -/* - * drivers/s390/net/iucv.h - * IUCV base support. - * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com) - * Xenia Tkatschow (xenia@us.ibm.com) - * - * - * Functionality: - * To explore any of the IUCV functions, one must first register - * their program using iucv_register_program(). Once your program has - * successfully completed a register, it can exploit the other functions. - * For furthur reference on all IUCV functionality, refer to the - * CP Programming Services book, also available on the web - * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 - * - * Definition of Return Codes - * -All positive return codes including zero are reflected back - * from CP except for iucv_register_program. The definition of each - * return code can be found in CP Programming Services book. - * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 - * - Return Code of: - * (-EINVAL) Invalid value - * (-ENOMEM) storage allocation failed - * pgmask defined in iucv_register_program will be set depending on input - * paramters. - * - */ - -#include -#include - -/** - * Debug Facility stuff - */ -#define IUCV_DBF_SETUP_NAME "iucv_setup" -#define IUCV_DBF_SETUP_LEN 32 -#define IUCV_DBF_SETUP_PAGES 2 -#define IUCV_DBF_SETUP_NR_AREAS 1 -#define IUCV_DBF_SETUP_LEVEL 3 - -#define IUCV_DBF_DATA_NAME "iucv_data" -#define IUCV_DBF_DATA_LEN 128 -#define IUCV_DBF_DATA_PAGES 2 -#define IUCV_DBF_DATA_NR_AREAS 1 -#define IUCV_DBF_DATA_LEVEL 2 - -#define IUCV_DBF_TRACE_NAME "iucv_trace" -#define IUCV_DBF_TRACE_LEN 16 -#define IUCV_DBF_TRACE_PAGES 4 -#define IUCV_DBF_TRACE_NR_AREAS 1 -#define IUCV_DBF_TRACE_LEVEL 3 - -#define IUCV_DBF_TEXT(name,level,text) \ - do { \ - debug_text_event(iucv_dbf_##name,level,text); \ - } while (0) - -#define IUCV_DBF_HEX(name,level,addr,len) \ - do { \ - debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ - } while (0) - -DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); - -#define IUCV_DBF_TEXT_(name,level,text...) \ - do { \ - char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ - sprintf(iucv_dbf_txt_buf, text); \ - debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ - put_cpu_var(iucv_dbf_txt_buf); \ - } while (0) - -#define IUCV_DBF_SPRINTF(name,level,text...) \ - do { \ - debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ - debug_sprintf_event(iucv_dbf_trace, level, text ); \ - } while (0) - -/** - * some more debug stuff - */ -#define IUCV_HEXDUMP16(importance,header,ptr) \ -PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ - "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ - *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ - *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ - *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ - *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ - *(((char*)ptr)+12),*(((char*)ptr)+13), \ - *(((char*)ptr)+14),*(((char*)ptr)+15)); \ -PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ - "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ - *(((char*)ptr)+16),*(((char*)ptr)+17), \ - *(((char*)ptr)+18),*(((char*)ptr)+19), \ - *(((char*)ptr)+20),*(((char*)ptr)+21), \ - *(((char*)ptr)+22),*(((char*)ptr)+23), \ - *(((char*)ptr)+24),*(((char*)ptr)+25), \ - *(((char*)ptr)+26),*(((char*)ptr)+27), \ - *(((char*)ptr)+28),*(((char*)ptr)+29), \ - *(((char*)ptr)+30),*(((char*)ptr)+31)); - -static inline void -iucv_hex_dump(unsigned char *buf, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (i && !(i % 16)) - printk("\n"); - printk("%02x ", *(buf + i)); - } - printk("\n"); -} -/** - * end of debug stuff - */ - -#define uchar unsigned char -#define ushort unsigned short -#define ulong unsigned long -#define iucv_handle_t void * - -/* flags1: - * All flags are defined in the field IPFLAGS1 of each function - * and can be found in CP Programming Services. - * IPLOCAL - Indicates the connect can only be satisfied on the - * local system - * IPPRTY - Indicates a priority message - * IPQUSCE - Indicates you do not want to receive messages on a - * path until an iucv_resume is issued - * IPRMDATA - Indicates that the message is in the parameter list - */ -#define IPLOCAL 0x01 -#define IPPRTY 0x20 -#define IPQUSCE 0x40 -#define IPRMDATA 0x80 - -/* flags1_out: - * All flags are defined in the output field of IPFLAGS1 for each function - * and can be found in CP Programming Services. - * IPNORPY - Specifies this is a one-way message and no reply is expected. - * IPPRTY - Indicates a priority message is permitted. Defined in flags1. - */ -#define IPNORPY 0x10 - -#define Nonpriority_MessagePendingInterruptsFlag 0x80 -#define Priority_MessagePendingInterruptsFlag 0x40 -#define Nonpriority_MessageCompletionInterruptsFlag 0x20 -#define Priority_MessageCompletionInterruptsFlag 0x10 -#define IUCVControlInterruptsFlag 0x08 -#define AllInterrupts 0xf8 -/* - * Mapping of external interrupt buffers should be used with the corresponding - * interrupt types. - * Names: iucv_ConnectionPending -> connection pending - * iucv_ConnectionComplete -> connection complete - * iucv_ConnectionSevered -> connection severed - * iucv_ConnectionQuiesced -> connection quiesced - * iucv_ConnectionResumed -> connection resumed - * iucv_MessagePending -> message pending - * iucv_MessageComplete -> message complete - */ -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u16 ipmsglim; - u16 res1; - uchar ipvmid[8]; - uchar ipuser[16]; - u32 res3; - uchar ippollfg; - uchar res4[3]; -} iucv_ConnectionPending; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u16 ipmsglim; - u16 res1; - uchar res2[8]; - uchar ipuser[16]; - u32 res3; - uchar ippollfg; - uchar res4[3]; -} iucv_ConnectionComplete; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionSevered; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionQuiesced; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionResumed; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u32 ipmsgid; - u32 iptrgcls; - union u2 { - u32 iprmmsg1_u32; - uchar iprmmsg1[4]; - } ln1msg1; - union u1 { - u32 ipbfln1f; - uchar iprmmsg2[4]; - } ln1msg2; - u32 res1[3]; - u32 ipbfln2f; - uchar ippollfg; - uchar res2[3]; -} iucv_MessagePending; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u32 ipmsgid; - u32 ipaudit; - uchar iprmmsg[8]; - u32 ipsrccls; - u32 ipmsgtag; - u32 res; - u32 ipbfln2f; - uchar ippollfg; - uchar res2[3]; -} iucv_MessageComplete; - -/* - * iucv_interrupt_ops_t: Is a vector of functions that handle - * IUCV interrupts. - * Parameter list: - * eib - is a pointer to a 40-byte area described - * with one of the structures above. - * pgm_data - this data is strictly for the - * interrupt handler that is passed by - * the application. This may be an address - * or token. -*/ -typedef struct { - void (*ConnectionPending) (iucv_ConnectionPending * eib, - void *pgm_data); - void (*ConnectionComplete) (iucv_ConnectionComplete * eib, - void *pgm_data); - void (*ConnectionSevered) (iucv_ConnectionSevered * eib, - void *pgm_data); - void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib, - void *pgm_data); - void (*ConnectionResumed) (iucv_ConnectionResumed * eib, - void *pgm_data); - void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data); - void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data); -} iucv_interrupt_ops_t; - -/* - *iucv_array_t : Defines buffer array. - * Inside the array may be 31- bit addresses and 31-bit lengths. -*/ -typedef struct { - u32 address; - u32 length; -} iucv_array_t __attribute__ ((aligned (8))); - -extern struct bus_type iucv_bus; -extern struct device *iucv_root; - -/* -prototypes- */ -/* - * Name: iucv_register_program - * Purpose: Registers an application with IUCV - * Input: prmname - user identification - * userid - machine identification - * pgmmask - indicates which bits in the prmname and userid combined will be - * used to determine who is given control - * ops - address of vector of interrupt handlers - * pgm_data- application data passed to interrupt handlers - * Output: NA - * Return: address of handler - * (0) - Error occurred, registration not completed. - * NOTE: Exact cause of failure will be recorded in syslog. -*/ -iucv_handle_t iucv_register_program (uchar pgmname[16], - uchar userid[8], - uchar pgmmask[24], - iucv_interrupt_ops_t * ops, - void *pgm_data); - -/* - * Name: iucv_unregister_program - * Purpose: Unregister application with IUCV - * Input: address of handler - * Output: NA - * Return: (0) - Normal return - * (-EINVAL) - Internal error, wild pointer -*/ -int iucv_unregister_program (iucv_handle_t handle); - -/* - * Name: iucv_accept - * Purpose: This function is issued after the user receives a Connection Pending external - * interrupt and now wishes to complete the IUCV communication path. - * Input: pathid - u16 , Path identification number - * msglim_reqstd - u16, The number of outstanding messages requested. - * user_data - uchar[16], Data specified by the iucv_connect function. - * flags1 - int, Contains options for this path. - * -IPPRTY - 0x20- Specifies if you want to send priority message. - * -IPRMDATA - 0x80, Specifies whether your program can handle a message - * in the parameter list. - * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being - * established. - * handle - iucv_handle_t, Address of handler. - * pgm_data - void *, Application data passed to interrupt handlers. - * flags1_out - int * Contains information about the path - * - IPPRTY - 0x20, Indicates you may send priority messages. - * msglim - *u16, Number of outstanding messages. - * Output: return code from CP IUCV call. -*/ - -int iucv_accept (u16 pathid, - u16 msglim_reqstd, - uchar user_data[16], - int flags1, - iucv_handle_t handle, - void *pgm_data, int *flags1_out, u16 * msglim); - -/* - * Name: iucv_connect - * Purpose: This function establishes an IUCV path. Although the connect may complete - * successfully, you are not able to use the path until you receive an IUCV - * Connection Complete external interrupt. - * Input: pathid - u16 *, Path identification number - * msglim_reqstd - u16, Number of outstanding messages requested - * user_data - uchar[16], 16-byte user data - * userid - uchar[8], User identification - * system_name - uchar[8], 8-byte identifying the system name - * flags1 - int, Contains options for this path. - * -IPPRTY - 0x20, Specifies if you want to send priority message. - * -IPRMDATA - 0x80, Specifies whether your program can handle a message - * in the parameter list. - * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being - * established. - * -IPLOCAL - 0X01, Allows an application to force the partner to be on - * the local system. If local is specified then target class cannot be - * specified. - * flags1_out - int * Contains information about the path - * - IPPRTY - 0x20, Indicates you may send priority messages. - * msglim - * u16, Number of outstanding messages - * handle - iucv_handle_t, Address of handler - * pgm_data - void *, Application data passed to interrupt handlers - * Output: return code from CP IUCV call - * rc - return code from iucv_declare_buffer - * -EINVAL - Invalid handle passed by application - * -EINVAL - Pathid address is NULL - * add_pathid_result - Return code from internal function add_pathid -*/ -int - iucv_connect (u16 * pathid, - u16 msglim_reqstd, - uchar user_data[16], - uchar userid[8], - uchar system_name[8], - int flags1, - int *flags1_out, - u16 * msglim, iucv_handle_t handle, void *pgm_data); - -/* - * Name: iucv_purge - * Purpose: This function cancels a message that you have sent. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID of the message to be purged. - * srccls - Specifies the source message class. - * Output: audit - Contains information about asynchronous error - * that may have affected the normal completion - * of this message. - * Return: Return code from CP IUCV call. -*/ -int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit); -/* - * Name: iucv_query_maxconn - * Purpose: This function determines the maximum number of communication paths you - * may establish. - * Return: maxconn - ulong, Maximum number of connection the virtual machine may - * establish. -*/ -ulong iucv_query_maxconn (void); - -/* - * Name: iucv_query_bufsize - * Purpose: This function determines how large an external interrupt - * buffer IUCV requires to store information. - * Return: bufsize - ulong, Size of external interrupt buffer. - */ -ulong iucv_query_bufsize (void); - -/* - * Name: iucv_quiesce - * Purpose: This function temporarily suspends incoming messages on an - * IUCV path. You can later reactivate the path by invoking - * the iucv_resume function. - * Input: pathid - Path identification number - * user_data - 16-bytes of user data - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_quiesce (u16 pathid, uchar user_data[16]); - -/* - * Name: iucv_receive - * Purpose: This function receives messages that are being sent to you - * over established paths. Data will be returned in buffer for length of - * buflen. - * Input: - * pathid - Path identification number. - * buffer - Address of buffer to receive. - * buflen - Length of buffer to receive. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * Output: - * flags1_out: int *, Contains information about this path. - * IPNORPY - 0x10 Specifies this is a one-way message and no reply is - * expected. - * IPPRTY - 0x20 Specifies if you want to send priority message. - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address of buffer updated by the number - * of bytes you have received. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - buffer address is pointing to NULL -*/ -int iucv_receive (u16 pathid, - u32 msgid, - u32 trgcls, - void *buffer, - ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length); - - /* - * Name: iucv_receive_array - * Purpose: This function receives messages that are being sent to you - * over established paths. Data will be returned in first buffer for - * length of first buffer. - * Input: pathid - Path identification number. - * msgid - specifies the message ID. - * trgcls - Specifies target class. - * buffer - Address of array of buffers. - * buflen - Total length of buffers. - * Output: - * flags1_out: int *, Contains information about this path. - * IPNORPY - 0x10 Specifies this is a one-way message and no reply is - * expected. - * IPPRTY - 0x20 Specifies if you want to send priority message. - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address points to the current list entry IUCV - * is working on. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. - */ -int iucv_receive_array (u16 pathid, - u32 msgid, - u32 trgcls, - iucv_array_t * buffer, - ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length); - -/* - * Name: iucv_reject - * Purpose: The reject function refuses a specified message. Between the - * time you are notified of a message and the time that you - * complete the message, the message may be rejected. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_reject (u16 pathid, u32 msgid, u32 trgcls); - -/* - * Name: iucv_reply - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20, Specifies if you want to send priority message. - * buffer - Address of reply buffer. - * buflen - Length of reply buffer. - * Output: residual_buffer - Address of buffer updated by the number - * of bytes you have moved. - * residual_length - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_reply (u16 pathid, - u32 msgid, - u32 trgcls, - int flags1, - void *buffer, ulong buflen, ulong * residual_buffer, - ulong * residual_length); - -/* - * Name: iucv_reply_array - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * The array identifies a list of addresses and lengths of - * discontiguous buffers that contains the reply data. - * Input: pathid - Path identification number - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20, Specifies if you want to send priority message. - * buffer - Address of array of reply buffers. - * buflen - Total length of reply buffers. - * Output: residual_buffer - Address of buffer which IUCV is currently working on. - * residual_length - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_reply_array (u16 pathid, - u32 msgid, - u32 trgcls, - int flags1, - iucv_array_t * buffer, - ulong buflen, ulong * residual_address, - ulong * residual_length); - -/* - * Name: iucv_reply_prmmsg - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Prmmsg signifies the data is moved into the - * parameter list. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into the parameter. - * list. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_reply_prmmsg (u16 pathid, - u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]); - -/* - * Name: iucv_resume - * Purpose: This function restores communications over a quiesced path - * Input: pathid - Path identification number. - * user_data - 16-bytes of user data. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_resume (u16 pathid, uchar user_data[16]); - -/* - * Name: iucv_send - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer and this is a - * one-way message and the receiver will not reply to the - * message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Address of send buffer. - * buflen - Length of send buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen); - -/* - * Name: iucv_send_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated witht the message. - * flags1 - Option for path. - * IPPRTY- specifies if you want to send priority message. - * buffer - Address of array of send buffers. - * buflen - Total length of send buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, iucv_array_t * buffer, ulong buflen); - -/* - * Name: iucv_send_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into parameter list. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. -*/ -int iucv_send_prmmsg (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]); - -/* - * Name: iucv_send2way - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer. The receiver - * of the send is expected to reply to the message and - * a buffer is provided into which IUCV moves the reply - * to this message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Address of send buffer. - * buflen - Length of send buffer. - * ansbuf - Address of buffer into which IUCV moves the reply of - * this message. - * anslen - Address of length of buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer or ansbuf address is NULL. -*/ -int iucv_send2way (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - void *buffer, ulong buflen, void *ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. The receiver of the send is expected to - * reply to the message and a buffer is provided into which - * IUCV moves the reply to this message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Sddress of array of send buffers. - * buflen - Total length of send buffers. - * ansbuf - Address of array of buffer into which IUCV moves the reply - * of this message. - * anslen - Address of length reply buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send2way_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - iucv_array_t * buffer, - ulong buflen, iucv_array_t * ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. - * Input: pathid - Rath identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed in parameter list. - * ansbuf - Address of buffer into which IUCV moves the reply of - * this message. - * anslen - Address of length of buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send2way_prmmsg (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - ulong flags1, - uchar prmmsg[8], void *ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_prmmsg_array - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. The contents of ansbuf is the address of the - * array of addresses and lengths of discontiguous buffers - * that contain the reply. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into the parameter list. - * ansbuf - Address of array of buffer into which IUCV moves the reply - * of this message. - * anslen - Address of length of reply buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Ansbuf address is NULL. -*/ -int iucv_send2way_prmmsg_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - uchar prmmsg[8], - iucv_array_t * ansbuf, ulong anslen); - -/* - * Name: iucv_setmask - * Purpose: This function enables or disables the following IUCV - * external interruptions: Nonpriority and priority message - * interrupts, nonpriority and priority reply interrupts. - * Input: SetMaskFlag - options for interrupts - * 0x80 - Nonpriority_MessagePendingInterruptsFlag - * 0x40 - Priority_MessagePendingInterruptsFlag - * 0x20 - Nonpriority_MessageCompletionInterruptsFlag - * 0x10 - Priority_MessageCompletionInterruptsFlag - * 0x08 - IUCVControlInterruptsFlag - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_setmask (int SetMaskFlag); - -/* - * Name: iucv_sever - * Purpose: This function terminates an IUCV path. - * Input: pathid - Path identification number. - * user_data - 16-bytes of user data. - * Output: NA - * Return: Return code from CP IUCV call. - * (-EINVAL) - Interal error, wild pointer. -*/ -int iucv_sever (u16 pathid, uchar user_data[16]); diff --git a/trunk/drivers/s390/net/netiucv.c b/trunk/drivers/s390/net/netiucv.c index 3346088f47e0..6387b483f2bf 100644 --- a/trunk/drivers/s390/net/netiucv.c +++ b/trunk/drivers/s390/net/netiucv.c @@ -1,7 +1,7 @@ /* * IUCV network driver * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * * Sysfs integration and all bugs therein by Cornelia Huck @@ -58,13 +58,94 @@ #include #include -#include "iucv.h" +#include #include "fsm.h" MODULE_AUTHOR ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)"); MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); +/** + * Debug Facility stuff + */ +#define IUCV_DBF_SETUP_NAME "iucv_setup" +#define IUCV_DBF_SETUP_LEN 32 +#define IUCV_DBF_SETUP_PAGES 2 +#define IUCV_DBF_SETUP_NR_AREAS 1 +#define IUCV_DBF_SETUP_LEVEL 3 + +#define IUCV_DBF_DATA_NAME "iucv_data" +#define IUCV_DBF_DATA_LEN 128 +#define IUCV_DBF_DATA_PAGES 2 +#define IUCV_DBF_DATA_NR_AREAS 1 +#define IUCV_DBF_DATA_LEVEL 2 + +#define IUCV_DBF_TRACE_NAME "iucv_trace" +#define IUCV_DBF_TRACE_LEN 16 +#define IUCV_DBF_TRACE_PAGES 4 +#define IUCV_DBF_TRACE_NR_AREAS 1 +#define IUCV_DBF_TRACE_LEVEL 3 + +#define IUCV_DBF_TEXT(name,level,text) \ + do { \ + debug_text_event(iucv_dbf_##name,level,text); \ + } while (0) + +#define IUCV_DBF_HEX(name,level,addr,len) \ + do { \ + debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ + } while (0) + +DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); + +#define IUCV_DBF_TEXT_(name,level,text...) \ + do { \ + char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ + sprintf(iucv_dbf_txt_buf, text); \ + debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ + put_cpu_var(iucv_dbf_txt_buf); \ + } while (0) + +#define IUCV_DBF_SPRINTF(name,level,text...) \ + do { \ + debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ + debug_sprintf_event(iucv_dbf_trace, level, text ); \ + } while (0) + +/** + * some more debug stuff + */ +#define IUCV_HEXDUMP16(importance,header,ptr) \ +PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ + "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ + *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ + *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ + *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ + *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ + *(((char*)ptr)+12),*(((char*)ptr)+13), \ + *(((char*)ptr)+14),*(((char*)ptr)+15)); \ +PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ + "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ + *(((char*)ptr)+16),*(((char*)ptr)+17), \ + *(((char*)ptr)+18),*(((char*)ptr)+19), \ + *(((char*)ptr)+20),*(((char*)ptr)+21), \ + *(((char*)ptr)+22),*(((char*)ptr)+23), \ + *(((char*)ptr)+24),*(((char*)ptr)+25), \ + *(((char*)ptr)+26),*(((char*)ptr)+27), \ + *(((char*)ptr)+28),*(((char*)ptr)+29), \ + *(((char*)ptr)+30),*(((char*)ptr)+31)); + +static inline void iucv_hex_dump(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (i && !(i % 16)) + printk("\n"); + printk("%02x ", *(buf + i)); + } + printk("\n"); +} #define PRINTK_HEADER " iucv: " /* for debugging */ @@ -73,6 +154,25 @@ static struct device_driver netiucv_driver = { .bus = &iucv_bus, }; +static int netiucv_callback_connreq(struct iucv_path *, + u8 ipvmid[8], u8 ipuser[16]); +static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *); +static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *); + +static struct iucv_handler netiucv_handler = { + .path_pending = netiucv_callback_connreq, + .path_complete = netiucv_callback_connack, + .path_severed = netiucv_callback_connrej, + .path_quiesced = netiucv_callback_connsusp, + .path_resumed = netiucv_callback_connres, + .message_pending = netiucv_callback_rx, + .message_complete = netiucv_callback_txdone +}; + /** * Per connection profiling data */ @@ -92,9 +192,8 @@ struct connection_profile { * Representation of one iucv connection */ struct iucv_connection { - struct iucv_connection *next; - iucv_handle_t handle; - __u16 pathid; + struct list_head list; + struct iucv_path *path; struct sk_buff *rx_buff; struct sk_buff *tx_buff; struct sk_buff_head collect_queue; @@ -112,12 +211,9 @@ struct iucv_connection { /** * Linked list of all connection structs. */ -struct iucv_connection_struct { - struct iucv_connection *iucv_connections; - rwlock_t iucv_rwlock; -}; - -static struct iucv_connection_struct iucv_conns; +static struct list_head iucv_connection_list = + LIST_HEAD_INIT(iucv_connection_list); +static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED; /** * Representation of event-data for the @@ -142,11 +238,11 @@ struct netiucv_priv { /** * Link level header for a packet. */ -typedef struct ll_header_t { - __u16 next; -} ll_header; +struct ll_header { + u16 next; +}; -#define NETIUCV_HDRLEN (sizeof(ll_header)) +#define NETIUCV_HDRLEN (sizeof(struct ll_header)) #define NETIUCV_BUFSIZE_MAX 32768 #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) @@ -158,35 +254,25 @@ typedef struct ll_header_t { * Compatibility macros for busy handling * of network devices. */ -static __inline__ void netiucv_clear_busy(struct net_device *dev) +static inline void netiucv_clear_busy(struct net_device *dev) { - clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy)); + struct netiucv_priv *priv = netdev_priv(dev); + clear_bit(0, &priv->tbusy); netif_wake_queue(dev); } -static __inline__ int netiucv_test_and_set_busy(struct net_device *dev) +static inline int netiucv_test_and_set_busy(struct net_device *dev) { + struct netiucv_priv *priv = netdev_priv(dev); netif_stop_queue(dev); - return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy); + return test_and_set_bit(0, &priv->tbusy); } -static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static __u8 iucvMagic[16] = { +static u8 iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 }; -/** - * This mask means the 16-byte IUCV "magic" and the origin userid must - * match exactly as specified in order to give connection_pending() - * control. - */ -static __u8 netiucv_mask[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - /** * Convert an iucv userId to its printable * form (strip whitespace at end). @@ -195,8 +281,7 @@ static __u8 netiucv_mask[] = { * * @returns The printable string (static data!!) */ -static __inline__ char * -netiucv_printname(char *name) +static inline char *netiucv_printname(char *name) { static char tmp[9]; char *p = tmp; @@ -379,8 +464,7 @@ static debug_info_t *iucv_dbf_trace = NULL; DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf); -static void -iucv_unregister_dbf_views(void) +static void iucv_unregister_dbf_views(void) { if (iucv_dbf_setup) debug_unregister(iucv_dbf_setup); @@ -389,8 +473,7 @@ iucv_unregister_dbf_views(void) if (iucv_dbf_trace) debug_unregister(iucv_dbf_trace); } -static int -iucv_register_dbf_views(void) +static int iucv_register_dbf_views(void) { iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, IUCV_DBF_SETUP_PAGES, @@ -422,125 +505,111 @@ iucv_register_dbf_views(void) return 0; } -/** +/* * Callback-wrappers, called from lowlevel iucv layer. - *****************************************************************************/ + */ -static void -netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data) +static void netiucv_callback_rx(struct iucv_path *path, + struct iucv_message *msg) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; - ev.data = (void *)eib; - + ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_RX, &ev); } -static void -netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data) +static void netiucv_callback_txdone(struct iucv_path *path, + struct iucv_message *msg) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; - ev.data = (void *)eib; + ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev); } -static void -netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data) +static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn); } -static void -netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data) +static int netiucv_callback_connreq(struct iucv_path *path, + u8 ipvmid[8], u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; + int rc; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); + if (memcmp(iucvMagic, ipuser, sizeof(ipuser))) + /* ipuser must match iucvMagic. */ + return -EINVAL; + rc = -EINVAL; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(conn, &iucv_connection_list, list) { + if (strncmp(ipvmid, conn->userid, 8)) + continue; + /* Found a matching connection for this path. */ + conn->path = path; + ev.conn = conn; + ev.data = path; + fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); + rc = 0; + } + read_unlock_bh(&iucv_connection_rwlock); + return rc; } -static void -netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data) +static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn); } -static void -netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data) +static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn); } -static void -netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data) +static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev); -} - -static iucv_interrupt_ops_t netiucv_ops = { - .ConnectionPending = netiucv_callback_connreq, - .ConnectionComplete = netiucv_callback_connack, - .ConnectionSevered = netiucv_callback_connrej, - .ConnectionQuiesced = netiucv_callback_connsusp, - .ConnectionResumed = netiucv_callback_connres, - .MessagePending = netiucv_callback_rx, - .MessageComplete = netiucv_callback_txdone -}; + fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn); +} /** * Dummy NOP action for all statemachines */ -static void -fsm_action_nop(fsm_instance *fi, int event, void *arg) +static void fsm_action_nop(fsm_instance *fi, int event, void *arg) { } -/** +/* * Actions of the connection statemachine - *****************************************************************************/ + */ /** - * Helper function for conn_action_rx() - * Unpack a just received skb and hand it over to - * upper layers. + * netiucv_unpack_skb + * @conn: The connection where this skb has been received. + * @pskb: The received skb. * - * @param conn The connection where this skb has been received. - * @param pskb The received skb. + * Unpack a just received skb and hand it over to upper layers. + * Helper function for conn_action_rx. */ -//static __inline__ void -static void -netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) +static void netiucv_unpack_skb(struct iucv_connection *conn, + struct sk_buff *pskb) { struct net_device *dev = conn->netdev; - struct netiucv_priv *privptr = dev->priv; - __u16 offset = 0; + struct netiucv_priv *privptr = netdev_priv(dev); + u16 offset = 0; skb_put(pskb, NETIUCV_HDRLEN); pskb->dev = dev; @@ -549,7 +618,7 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) while (1) { struct sk_buff *skb; - ll_header *header = (ll_header *)pskb->data; + struct ll_header *header = (struct ll_header *) pskb->data; if (!header->next) break; @@ -595,40 +664,37 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) } } -static void -conn_action_rx(fsm_instance *fi, int event, void *arg) +static void conn_action_rx(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_MessagePending *eib = (iucv_MessagePending *)ev->data; - struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv; - - __u32 msglen = eib->ln1msg2.ipbfln1f; + struct iucv_message *msg = ev->data; + struct netiucv_priv *privptr = netdev_priv(conn->netdev); int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); if (!conn->netdev) { - /* FRITZ: How to tell iucv LL to drop the msg? */ + iucv_message_reject(conn->path, msg); PRINT_WARN("Received data for unlinked connection\n"); IUCV_DBF_TEXT(data, 2, - "Received data for unlinked connection\n"); + "Received data for unlinked connection\n"); return; } - if (msglen > conn->max_buffsize) { - /* FRITZ: How to tell iucv LL to drop the msg? */ + if (msg->length > conn->max_buffsize) { + iucv_message_reject(conn->path, msg); privptr->stats.rx_dropped++; PRINT_WARN("msglen %d > max_buffsize %d\n", - msglen, conn->max_buffsize); + msg->length, conn->max_buffsize); IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", - msglen, conn->max_buffsize); + msg->length, conn->max_buffsize); return; } conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; conn->rx_buff->len = 0; - rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls, - conn->rx_buff->data, msglen, NULL, NULL, NULL); - if (rc || msglen < 5) { + rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data, + msg->length, NULL); + if (rc || msg->length < 5) { privptr->stats.rx_errors++; PRINT_WARN("iucv_receive returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); @@ -637,26 +703,26 @@ conn_action_rx(fsm_instance *fi, int event, void *arg) netiucv_unpack_skb(conn, conn->rx_buff); } -static void -conn_action_txdone(fsm_instance *fi, int event, void *arg) +static void conn_action_txdone(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data; + struct iucv_message *msg = ev->data; + struct iucv_message txmsg; struct netiucv_priv *privptr = NULL; - /* Shut up, gcc! skb is always below 2G. */ - __u32 single_flag = eib->ipmsgtag; - __u32 txbytes = 0; - __u32 txpackets = 0; - __u32 stat_maxcq = 0; + u32 single_flag = msg->tag; + u32 txbytes = 0; + u32 txpackets = 0; + u32 stat_maxcq = 0; struct sk_buff *skb; unsigned long saveflags; - ll_header header; + struct ll_header header; + int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); - if (conn && conn->netdev && conn->netdev->priv) - privptr = (struct netiucv_priv *)conn->netdev->priv; + if (conn && conn->netdev) + privptr = netdev_priv(conn->netdev); conn->prof.tx_pending--; if (single_flag) { if ((skb = skb_dequeue(&conn->commit_queue))) { @@ -688,56 +754,55 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg) conn->prof.maxmulti = conn->collect_len; conn->collect_len = 0; spin_unlock_irqrestore(&conn->collect_lock, saveflags); - if (conn->tx_buff->len) { - int rc; - - header.next = 0; - memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, - NETIUCV_HDRLEN); + if (conn->tx_buff->len == 0) { + fsm_newstate(fi, CONN_STATE_IDLE); + return; + } - conn->prof.send_stamp = xtime; - rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0, + header.next = 0; + memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); + conn->prof.send_stamp = xtime; + txmsg.class = 0; + txmsg.tag = 0; + rc = iucv_message_send(conn->path, &txmsg, 0, 0, conn->tx_buff->data, conn->tx_buff->len); - conn->prof.doios_multi++; - conn->prof.txlen += conn->tx_buff->len; - conn->prof.tx_pending++; - if (conn->prof.tx_pending > conn->prof.tx_max_pending) - conn->prof.tx_max_pending = conn->prof.tx_pending; - if (rc) { - conn->prof.tx_pending--; - fsm_newstate(fi, CONN_STATE_IDLE); - if (privptr) - privptr->stats.tx_errors += txpackets; - PRINT_WARN("iucv_send returned %08x\n", rc); - IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); - } else { - if (privptr) { - privptr->stats.tx_packets += txpackets; - privptr->stats.tx_bytes += txbytes; - } - if (stat_maxcq > conn->prof.maxcqueue) - conn->prof.maxcqueue = stat_maxcq; - } - } else + conn->prof.doios_multi++; + conn->prof.txlen += conn->tx_buff->len; + conn->prof.tx_pending++; + if (conn->prof.tx_pending > conn->prof.tx_max_pending) + conn->prof.tx_max_pending = conn->prof.tx_pending; + if (rc) { + conn->prof.tx_pending--; fsm_newstate(fi, CONN_STATE_IDLE); + if (privptr) + privptr->stats.tx_errors += txpackets; + PRINT_WARN("iucv_send returned %08x\n", rc); + IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); + } else { + if (privptr) { + privptr->stats.tx_packets += txpackets; + privptr->stats.tx_bytes += txbytes; + } + if (stat_maxcq > conn->prof.maxcqueue) + conn->prof.maxcqueue = stat_maxcq; + } } -static void -conn_action_connaccept(fsm_instance *fi, int event, void *arg) +static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; + struct iucv_path *path = ev->data; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); int rc; - __u16 msglimit; - __u8 udata[16]; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0, - conn->handle, conn, NULL, &msglimit); + conn->path = path; + path->msglim = NETIUCV_QUEUELEN_DEFAULT; + path->flags = 0; + rc = iucv_path_accept(path, &netiucv_handler, NULL, conn); if (rc) { PRINT_WARN("%s: IUCV accept failed with error %d\n", netdev->name, rc); @@ -745,183 +810,126 @@ conn_action_connaccept(fsm_instance *fi, int event, void *arg) return; } fsm_newstate(fi, CONN_STATE_IDLE); - conn->pathid = eib->ippathid; - netdev->tx_queue_len = msglimit; + netdev->tx_queue_len = conn->path->msglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); } -static void -conn_action_connreject(fsm_instance *fi, int event, void *arg) +static void conn_action_connreject(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - struct net_device *netdev = conn->netdev; - iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; - __u8 udata[16]; + struct iucv_event *ev = arg; + struct iucv_path *path = ev->data; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - - iucv_sever(eib->ippathid, udata); - if (eib->ippathid != conn->pathid) { - PRINT_INFO("%s: IR Connection Pending; " - "pathid %d does not match original pathid %d\n", - netdev->name, eib->ippathid, conn->pathid); - IUCV_DBF_TEXT_(data, 2, - "connreject: IR pathid %d, conn. pathid %d\n", - eib->ippathid, conn->pathid); - iucv_sever(conn->pathid, udata); - } + iucv_path_sever(path, NULL); } -static void -conn_action_connack(fsm_instance *fi, int event, void *arg) +static void conn_action_connack(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_IDLE); - if (eib->ippathid != conn->pathid) { - PRINT_INFO("%s: IR Connection Complete; " - "pathid %d does not match original pathid %d\n", - netdev->name, eib->ippathid, conn->pathid); - IUCV_DBF_TEXT_(data, 2, - "connack: IR pathid %d, conn. pathid %d\n", - eib->ippathid, conn->pathid); - conn->pathid = eib->ippathid; - } - netdev->tx_queue_len = eib->ipmsglim; + netdev->tx_queue_len = conn->path->msglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); } -static void -conn_action_conntimsev(fsm_instance *fi, int event, void *arg) +static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg) { - struct iucv_connection *conn = (struct iucv_connection *)arg; - __u8 udata[16]; + struct iucv_connection *conn = arg; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - fsm_deltimer(&conn->timer); - iucv_sever(conn->pathid, udata); + iucv_path_sever(conn->path, NULL); fsm_newstate(fi, CONN_STATE_STARTWAIT); } -static void -conn_action_connsever(fsm_instance *fi, int event, void *arg) +static void conn_action_connsever(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; - __u8 udata[16]; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); - iucv_sever(conn->pathid, udata); + iucv_path_sever(conn->path, NULL); PRINT_INFO("%s: Remote dropped connection\n", netdev->name); IUCV_DBF_TEXT(data, 2, - "conn_action_connsever: Remote dropped connection\n"); + "conn_action_connsever: Remote dropped connection\n"); fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } -static void -conn_action_start(fsm_instance *fi, int event, void *arg) +static void conn_action_start(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - __u16 msglimit; + struct iucv_connection *conn = arg; int rc; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (!conn->handle) { - IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n"); - conn->handle = - iucv_register_program(iucvMagic, conn->userid, - netiucv_mask, - &netiucv_ops, conn); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - if (!conn->handle) { - fsm_newstate(fi, CONN_STATE_REGERR); - conn->handle = NULL; - IUCV_DBF_TEXT(setup, 2, - "NULL from iucv_register_program\n"); - return; - } - - PRINT_DEBUG("%s('%s'): registered successfully\n", - conn->netdev->name, conn->userid); - } - + fsm_newstate(fi, CONN_STATE_STARTWAIT); PRINT_DEBUG("%s('%s'): connecting ...\n", - conn->netdev->name, conn->userid); + conn->netdev->name, conn->userid); - /* We must set the state before calling iucv_connect because the callback - * handler could be called at any point after the connection request is - * sent */ + /* + * We must set the state before calling iucv_connect because the + * callback handler could be called at any point after the connection + * request is sent + */ fsm_newstate(fi, CONN_STATE_SETUPWAIT); - rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, - conn->userid, iucv_host, 0, NULL, &msglimit, - conn->handle, conn); + conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL); + rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid, + NULL, iucvMagic, conn); switch (rc) { - case 0: - conn->netdev->tx_queue_len = msglimit; - fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, - CONN_EVENT_TIMER, conn); - return; - case 11: - PRINT_INFO("%s: User %s is currently not available.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - return; - case 12: - PRINT_INFO("%s: User %s is currently not ready.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - return; - case 13: - PRINT_WARN("%s: Too many IUCV connections.\n", - conn->netdev->name); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - case 14: - PRINT_WARN( - "%s: User %s has too many IUCV connections.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - case 15: - PRINT_WARN( - "%s: No IUCV authorization in CP directory.\n", - conn->netdev->name); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - default: - PRINT_WARN("%s: iucv_connect returned error %d\n", - conn->netdev->name, rc); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; + case 0: + conn->netdev->tx_queue_len = conn->path->msglim; + fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, + CONN_EVENT_TIMER, conn); + return; + case 11: + PRINT_INFO("%s: User %s is currently not available.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 12: + PRINT_INFO("%s: User %s is currently not ready.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 13: + PRINT_WARN("%s: Too many IUCV connections.\n", + conn->netdev->name); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 14: + PRINT_WARN("%s: User %s has too many IUCV connections.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 15: + PRINT_WARN("%s: No IUCV authorization in CP directory.\n", + conn->netdev->name); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + default: + PRINT_WARN("%s: iucv_connect returned error %d\n", + conn->netdev->name, rc); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; } IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc); - IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); - iucv_unregister_program(conn->handle); - conn->handle = NULL; + kfree(conn->path); + conn->path = NULL; } -static void -netiucv_purge_skb_queue(struct sk_buff_head *q) +static void netiucv_purge_skb_queue(struct sk_buff_head *q) { struct sk_buff *skb; @@ -931,36 +939,34 @@ netiucv_purge_skb_queue(struct sk_buff_head *q) } } -static void -conn_action_stop(fsm_instance *fi, int event, void *arg) +static void conn_action_stop(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_STOPPED); netiucv_purge_skb_queue(&conn->collect_queue); - if (conn->handle) - IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); - iucv_unregister_program(conn->handle); - conn->handle = NULL; + if (conn->path) { + IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n"); + iucv_path_sever(conn->path, iucvMagic); + kfree(conn->path); + conn->path = NULL; + } netiucv_purge_skb_queue(&conn->commit_queue); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } -static void -conn_action_inval(fsm_instance *fi, int event, void *arg) +static void conn_action_inval(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - PRINT_WARN("%s: Cannot connect without username\n", - netdev->name); + PRINT_WARN("%s: Cannot connect without username\n", netdev->name); IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); } @@ -999,29 +1005,27 @@ static const fsm_node conn_fsm[] = { static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node); -/** +/* * Actions for interface - statemachine. - *****************************************************************************/ + */ /** - * Startup connection by sending CONN_EVENT_START to it. + * dev_action_start + * @fi: An instance of an interface statemachine. + * @event: The event, just happened. + * @arg: Generic pointer, casted from struct net_device * upon call. * - * @param fi An instance of an interface statemachine. - * @param event The event, just happened. - * @param arg Generic pointer, casted from struct net_device * upon call. + * Startup connection by sending CONN_EVENT_START to it. */ -static void -dev_action_start(fsm_instance *fi, int event, void *arg) +static void dev_action_start(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; - struct iucv_event ev; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - ev.conn = privptr->conn; fsm_newstate(fi, DEV_STATE_STARTWAIT); - fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev); + fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn); } /** @@ -1034,8 +1038,8 @@ dev_action_start(fsm_instance *fi, int event, void *arg) static void dev_action_stop(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); struct iucv_event ev; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -1057,8 +1061,8 @@ dev_action_stop(fsm_instance *fi, int event, void *arg) static void dev_action_connup(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -1131,11 +1135,13 @@ static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node); * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { +static int netiucv_transmit_skb(struct iucv_connection *conn, + struct sk_buff *skb) +{ + struct iucv_message msg; unsigned long saveflags; - ll_header header; - int rc = 0; + struct ll_header header; + int rc; if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) { int l = skb->len + NETIUCV_HDRLEN; @@ -1145,11 +1151,12 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { (conn->max_buffsize - NETIUCV_HDRLEN)) { rc = -EBUSY; IUCV_DBF_TEXT(data, 2, - "EBUSY from netiucv_transmit_skb\n"); + "EBUSY from netiucv_transmit_skb\n"); } else { atomic_inc(&skb->users); skb_queue_tail(&conn->collect_queue, skb); conn->collect_len += l; + rc = 0; } spin_unlock_irqrestore(&conn->collect_lock, saveflags); } else { @@ -1188,9 +1195,10 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { fsm_newstate(conn->fsm, CONN_STATE_TX); conn->prof.send_stamp = xtime; - rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */, - 0, nskb->data, nskb->len); - /* Shut up, gcc! nskb is always below 2G. */ + msg.tag = 1; + msg.class = 0; + rc = iucv_message_send(conn->path, &msg, 0, 0, + nskb->data, nskb->len); conn->prof.doios_single++; conn->prof.txlen += skb->len; conn->prof.tx_pending++; @@ -1200,7 +1208,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { struct netiucv_priv *privptr; fsm_newstate(conn->fsm, CONN_STATE_IDLE); conn->prof.tx_pending--; - privptr = (struct netiucv_priv *)conn->netdev->priv; + privptr = netdev_priv(conn->netdev); if (privptr) privptr->stats.tx_errors++; if (copied) @@ -1226,9 +1234,9 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { return rc; } -/** +/* * Interface API for upper network layers - *****************************************************************************/ + */ /** * Open an interface. @@ -1238,9 +1246,11 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_open(struct net_device *dev) { - fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev); +static int netiucv_open(struct net_device *dev) +{ + struct netiucv_priv *priv = netdev_priv(dev); + + fsm_event(priv->fsm, DEV_EVENT_START, dev); return 0; } @@ -1252,9 +1262,11 @@ netiucv_open(struct net_device *dev) { * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_close(struct net_device *dev) { - fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev); +static int netiucv_close(struct net_device *dev) +{ + struct netiucv_priv *priv = netdev_priv(dev); + + fsm_event(priv->fsm, DEV_EVENT_STOP, dev); return 0; } @@ -1271,8 +1283,8 @@ netiucv_close(struct net_device *dev) { */ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) { - int rc = 0; - struct netiucv_priv *privptr = dev->priv; + struct netiucv_priv *privptr = netdev_priv(dev); + int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); /** @@ -1312,40 +1324,41 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) return -EBUSY; } dev->trans_start = jiffies; - if (netiucv_transmit_skb(privptr->conn, skb)) - rc = 1; + rc = netiucv_transmit_skb(privptr->conn, skb) != 0; netiucv_clear_busy(dev); return rc; } /** - * Returns interface statistics of a device. + * netiucv_stats + * @dev: Pointer to interface struct. * - * @param dev Pointer to interface struct. + * Returns interface statistics of a device. * - * @return Pointer to stats struct of this interface. + * Returns pointer to stats struct of this interface. */ -static struct net_device_stats * -netiucv_stats (struct net_device * dev) +static struct net_device_stats *netiucv_stats (struct net_device * dev) { + struct netiucv_priv *priv = netdev_priv(dev); + IUCV_DBF_TEXT(trace, 5, __FUNCTION__); - return &((struct netiucv_priv *)dev->priv)->stats; + return &priv->stats; } /** - * Sets MTU of an interface. + * netiucv_change_mtu + * @dev: Pointer to interface struct. + * @new_mtu: The new MTU to use for this interface. * - * @param dev Pointer to interface struct. - * @param new_mtu The new MTU to use for this interface. + * Sets MTU of an interface. * - * @return 0 on success, -EINVAL if MTU is out of valid range. + * Returns 0 on success, -EINVAL if MTU is out of valid range. * (valid range is 576 .. NETIUCV_MTU_MAX). */ -static int -netiucv_change_mtu (struct net_device * dev, int new_mtu) +static int netiucv_change_mtu(struct net_device * dev, int new_mtu) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) { + if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) { IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n"); return -EINVAL; } @@ -1353,12 +1366,12 @@ netiucv_change_mtu (struct net_device * dev, int new_mtu) return 0; } -/** +/* * attributes in sysfs - *****************************************************************************/ + */ -static ssize_t -user_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t user_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1366,8 +1379,8 @@ user_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); } -static ssize_t -user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t user_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1375,80 +1388,70 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, char *tmp; char username[9]; int i; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct iucv_connection *cp; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (count>9) { - PRINT_WARN("netiucv: username too long (%d)!\n", (int)count); + if (count > 9) { + PRINT_WARN("netiucv: username too long (%d)!\n", (int) count); IUCV_DBF_TEXT_(setup, 2, - "%d is length of username\n", (int)count); + "%d is length of username\n", (int) count); return -EINVAL; } tmp = strsep((char **) &buf, "\n"); - for (i=0, p=tmp; i<8 && *p; i++, p++) { - if (isalnum(*p) || (*p == '$')) + for (i = 0, p = tmp; i < 8 && *p; i++, p++) { + if (isalnum(*p) || (*p == '$')) { username[i]= toupper(*p); - else if (*p == '\n') { + continue; + } + if (*p == '\n') { /* trailing lf, grr */ break; - } else { - PRINT_WARN("netiucv: Invalid char %c in username!\n", - *p); - IUCV_DBF_TEXT_(setup, 2, - "username: invalid character %c\n", - *p); - return -EINVAL; } + PRINT_WARN("netiucv: Invalid char %c in username!\n", *p); + IUCV_DBF_TEXT_(setup, 2, + "username: invalid character %c\n", *p); + return -EINVAL; } - while (i<8) + while (i < 8) username[i++] = ' '; username[8] = '\0'; - if (memcmp(username, priv->conn->userid, 9)) { - /* username changed */ - if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - PRINT_WARN( - "netiucv: device %s active, connected to %s\n", - dev->bus_id, priv->conn->userid); - PRINT_WARN("netiucv: user cannot be updated\n"); - IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); - return -EBUSY; + if (memcmp(username, priv->conn->userid, 9) && + (ndev->flags & (IFF_UP | IFF_RUNNING))) { + /* username changed while the interface is active. */ + PRINT_WARN("netiucv: device %s active, connected to %s\n", + dev->bus_id, priv->conn->userid); + PRINT_WARN("netiucv: user cannot be updated\n"); + IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); + return -EBUSY; + } + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) { + read_unlock_bh(&iucv_connection_rwlock); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); + return -EEXIST; } } - read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (!strncmp(username, (*clist)->userid, 9) || - ((*clist)->netdev != ndev)) - break; - clist = &((*clist)->next); - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (*clist) { - PRINT_WARN("netiucv: Connection to %s already exists\n", - username); - return -EEXIST; - } + read_unlock_bh(&iucv_connection_rwlock); memcpy(priv->conn->userid, username, 9); - return count; - } static DEVICE_ATTR(user, 0644, user_show, user_write); -static ssize_t -buffer_show (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct netiucv_priv *priv = dev->driver_data; +static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, + char *buf) +{ struct netiucv_priv *priv = dev->driver_data; IUCV_DBF_TEXT(trace, 5, __FUNCTION__); return sprintf(buf, "%d\n", priv->conn->max_buffsize); } -static ssize_t -buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1502,8 +1505,8 @@ buffer_write (struct device *dev, struct device_attribute *attr, const char *buf static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); -static ssize_t -dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1513,8 +1516,8 @@ dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); -static ssize_t -conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t conn_fsm_show (struct device *dev, + struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1524,8 +1527,8 @@ conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); -static ssize_t -maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t maxmulti_show (struct device *dev, + struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1533,8 +1536,9 @@ maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); } -static ssize_t -maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t maxmulti_write (struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1545,8 +1549,8 @@ maxmulti_write (struct device *dev, struct device_attribute *attr, const char *b static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); -static ssize_t -maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1554,8 +1558,8 @@ maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); } -static ssize_t -maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1566,8 +1570,8 @@ maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); -static ssize_t -sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1575,8 +1579,8 @@ sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); } -static ssize_t -sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1587,8 +1591,8 @@ sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); -static ssize_t -mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1596,8 +1600,8 @@ mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); } -static ssize_t -mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1608,8 +1612,8 @@ mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); -static ssize_t -txlen_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1617,8 +1621,8 @@ txlen_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.txlen); } -static ssize_t -txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1629,8 +1633,8 @@ txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); -static ssize_t -txtime_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1638,8 +1642,8 @@ txtime_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); } -static ssize_t -txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1650,8 +1654,8 @@ txtime_write (struct device *dev, struct device_attribute *attr, const char *buf static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); -static ssize_t -txpend_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1659,8 +1663,8 @@ txpend_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); } -static ssize_t -txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1671,8 +1675,8 @@ txpend_write (struct device *dev, struct device_attribute *attr, const char *buf static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); -static ssize_t -txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1680,8 +1684,8 @@ txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); } -static ssize_t -txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1721,8 +1725,7 @@ static struct attribute_group netiucv_stat_attr_group = { .attrs = netiucv_stat_attrs, }; -static inline int -netiucv_add_files(struct device *dev) +static inline int netiucv_add_files(struct device *dev) { int ret; @@ -1736,18 +1739,16 @@ netiucv_add_files(struct device *dev) return ret; } -static inline void -netiucv_remove_files(struct device *dev) +static inline void netiucv_remove_files(struct device *dev) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); sysfs_remove_group(&dev->kobj, &netiucv_attr_group); } -static int -netiucv_register_device(struct net_device *ndev) +static int netiucv_register_device(struct net_device *ndev) { - struct netiucv_priv *priv = ndev->priv; + struct netiucv_priv *priv = netdev_priv(ndev); struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); int ret; @@ -1786,8 +1787,7 @@ netiucv_register_device(struct net_device *ndev) return ret; } -static void -netiucv_unregister_device(struct device *dev) +static void netiucv_unregister_device(struct device *dev) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); netiucv_remove_files(dev); @@ -1798,107 +1798,89 @@ netiucv_unregister_device(struct device *dev) * Allocate and initialize a new connection structure. * Add it to the list of netiucv connections; */ -static struct iucv_connection * -netiucv_new_connection(struct net_device *dev, char *username) -{ - unsigned long flags; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - struct iucv_connection *conn = - kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); - - if (conn) { - skb_queue_head_init(&conn->collect_queue); - skb_queue_head_init(&conn->commit_queue); - spin_lock_init(&conn->collect_lock); - conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; - conn->netdev = dev; - - conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, - GFP_KERNEL | GFP_DMA); - if (!conn->rx_buff) { - kfree(conn); - return NULL; - } - conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, - GFP_KERNEL | GFP_DMA); - if (!conn->tx_buff) { - kfree_skb(conn->rx_buff); - kfree(conn); - return NULL; - } - conn->fsm = init_fsm("netiucvconn", conn_state_names, - conn_event_names, NR_CONN_STATES, - NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, - GFP_KERNEL); - if (!conn->fsm) { - kfree_skb(conn->tx_buff); - kfree_skb(conn->rx_buff); - kfree(conn); - return NULL; - } - fsm_settimer(conn->fsm, &conn->timer); - fsm_newstate(conn->fsm, CONN_STATE_INVALID); - - if (username) { - memcpy(conn->userid, username, 9); - fsm_newstate(conn->fsm, CONN_STATE_STOPPED); - } +static struct iucv_connection *netiucv_new_connection(struct net_device *dev, + char *username) +{ + struct iucv_connection *conn; - write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - conn->next = *clist; - *clist = conn; - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + goto out; + skb_queue_head_init(&conn->collect_queue); + skb_queue_head_init(&conn->commit_queue); + spin_lock_init(&conn->collect_lock); + conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; + conn->netdev = dev; + + conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); + if (!conn->rx_buff) + goto out_conn; + conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); + if (!conn->tx_buff) + goto out_rx; + conn->fsm = init_fsm("netiucvconn", conn_state_names, + conn_event_names, NR_CONN_STATES, + NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, + GFP_KERNEL); + if (!conn->fsm) + goto out_tx; + + fsm_settimer(conn->fsm, &conn->timer); + fsm_newstate(conn->fsm, CONN_STATE_INVALID); + + if (username) { + memcpy(conn->userid, username, 9); + fsm_newstate(conn->fsm, CONN_STATE_STOPPED); } + + write_lock_bh(&iucv_connection_rwlock); + list_add_tail(&conn->list, &iucv_connection_list); + write_unlock_bh(&iucv_connection_rwlock); return conn; + +out_tx: + kfree_skb(conn->tx_buff); +out_rx: + kfree_skb(conn->rx_buff); +out_conn: + kfree(conn); +out: + return NULL; } /** * Release a connection structure and remove it from the * list of netiucv connections. */ -static void -netiucv_remove_connection(struct iucv_connection *conn) +static void netiucv_remove_connection(struct iucv_connection *conn) { - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (conn == NULL) - return; - write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (*clist == conn) { - *clist = conn->next; - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (conn->handle) { - iucv_unregister_program(conn->handle); - conn->handle = NULL; - } - fsm_deltimer(&conn->timer); - kfree_fsm(conn->fsm); - kfree_skb(conn->rx_buff); - kfree_skb(conn->tx_buff); - return; - } - clist = &((*clist)->next); + write_lock_bh(&iucv_connection_rwlock); + list_del_init(&conn->list); + write_unlock_bh(&iucv_connection_rwlock); + if (conn->path) { + iucv_path_sever(conn->path, iucvMagic); + kfree(conn->path); + conn->path = NULL; } - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + fsm_deltimer(&conn->timer); + kfree_fsm(conn->fsm); + kfree_skb(conn->rx_buff); + kfree_skb(conn->tx_buff); } /** * Release everything of a net device. */ -static void -netiucv_free_netdevice(struct net_device *dev) +static void netiucv_free_netdevice(struct net_device *dev) { - struct netiucv_priv *privptr; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); if (!dev) return; - privptr = (struct netiucv_priv *)dev->priv; if (privptr) { if (privptr->conn) netiucv_remove_connection(privptr->conn); @@ -1913,11 +1895,8 @@ netiucv_free_netdevice(struct net_device *dev) /** * Initialize a net device. (Called from kernel in alloc_netdev()) */ -static void -netiucv_setup_netdevice(struct net_device *dev) +static void netiucv_setup_netdevice(struct net_device *dev) { - memset(dev->priv, 0, sizeof(struct netiucv_priv)); - dev->mtu = NETIUCV_MTU_DEFAULT; dev->hard_start_xmit = netiucv_tx; dev->open = netiucv_open; @@ -1936,8 +1915,7 @@ netiucv_setup_netdevice(struct net_device *dev) /** * Allocate and initialize everything of a net device. */ -static struct net_device * -netiucv_init_netdevice(char *username) +static struct net_device *netiucv_init_netdevice(char *username) { struct netiucv_priv *privptr; struct net_device *dev; @@ -1946,40 +1924,40 @@ netiucv_init_netdevice(char *username) netiucv_setup_netdevice); if (!dev) return NULL; - if (dev_alloc_name(dev, dev->name) < 0) { - free_netdev(dev); - return NULL; - } + if (dev_alloc_name(dev, dev->name) < 0) + goto out_netdev; - privptr = (struct netiucv_priv *)dev->priv; + privptr = netdev_priv(dev); privptr->fsm = init_fsm("netiucvdev", dev_state_names, dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS, dev_fsm, DEV_FSM_LEN, GFP_KERNEL); - if (!privptr->fsm) { - free_netdev(dev); - return NULL; - } + if (!privptr->fsm) + goto out_netdev; + privptr->conn = netiucv_new_connection(dev, username); if (!privptr->conn) { - kfree_fsm(privptr->fsm); - free_netdev(dev); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); - return NULL; + goto out_fsm; } fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); - return dev; + +out_fsm: + kfree_fsm(privptr->fsm); +out_netdev: + free_netdev(dev); + return NULL; } -static ssize_t -conn_write(struct device_driver *drv, const char *buf, size_t count) +static ssize_t conn_write(struct device_driver *drv, + const char *buf, size_t count) { - char *p; + const char *p; char username[9]; - int i, ret; + int i, rc; struct net_device *dev; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct netiucv_priv *priv; + struct iucv_connection *cp; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); if (count>9) { @@ -1988,83 +1966,82 @@ conn_write(struct device_driver *drv, const char *buf, size_t count) return -EINVAL; } - for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { - if (isalnum(*p) || (*p == '$')) - username[i]= toupper(*p); - else if (*p == '\n') { + for (i = 0, p = buf; i < 8 && *p; i++, p++) { + if (isalnum(*p) || *p == '$') { + username[i] = toupper(*p); + continue; + } + if (*p == '\n') /* trailing lf, grr */ break; - } else { - PRINT_WARN("netiucv: Invalid character in username!\n"); - IUCV_DBF_TEXT_(setup, 2, - "conn_write: invalid character %c\n", *p); - return -EINVAL; - } + PRINT_WARN("netiucv: Invalid character in username!\n"); + IUCV_DBF_TEXT_(setup, 2, + "conn_write: invalid character %c\n", *p); + return -EINVAL; } - while (i<8) + while (i < 8) username[i++] = ' '; username[8] = '\0'; - read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (!strncmp(username, (*clist)->userid, 9)) - break; - clist = &((*clist)->next); - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (*clist) { - PRINT_WARN("netiucv: Connection to %s already exists\n", - username); - return -EEXIST; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + if (!strncmp(username, cp->userid, 9)) { + read_unlock_bh(&iucv_connection_rwlock); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); + return -EEXIST; + } } + read_unlock_bh(&iucv_connection_rwlock); + dev = netiucv_init_netdevice(username); if (!dev) { - PRINT_WARN( - "netiucv: Could not allocate network device structure " - "for user '%s'\n", netiucv_printname(username)); + PRINT_WARN("netiucv: Could not allocate network device " + "structure for user '%s'\n", + netiucv_printname(username)); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); return -ENODEV; } - if ((ret = netiucv_register_device(dev))) { + rc = netiucv_register_device(dev); + if (rc) { IUCV_DBF_TEXT_(setup, 2, - "ret %d from netiucv_register_device\n", ret); + "ret %d from netiucv_register_device\n", rc); goto out_free_ndev; } /* sysfs magic */ - SET_NETDEV_DEV(dev, - (struct device*)((struct netiucv_priv*)dev->priv)->dev); + priv = netdev_priv(dev); + SET_NETDEV_DEV(dev, priv->dev); - if ((ret = register_netdev(dev))) { - netiucv_unregister_device((struct device*) - ((struct netiucv_priv*)dev->priv)->dev); - goto out_free_ndev; - } + rc = register_netdev(dev); + if (rc) + goto out_unreg; PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username)); return count; +out_unreg: + netiucv_unregister_device(priv->dev); out_free_ndev: PRINT_WARN("netiucv: Could not register '%s'\n", dev->name); IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n"); netiucv_free_netdevice(dev); - return ret; + return rc; } static DRIVER_ATTR(connection, 0200, NULL, conn_write); -static ssize_t -remove_write (struct device_driver *drv, const char *buf, size_t count) +static ssize_t remove_write (struct device_driver *drv, + const char *buf, size_t count) { - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct iucv_connection *cp; struct net_device *ndev; struct netiucv_priv *priv; struct device *dev; char name[IFNAMSIZ]; - char *p; + const char *p; int i; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -2072,33 +2049,27 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) if (count >= IFNAMSIZ) count = IFNAMSIZ - 1;; - for (i=0, p=(char *)buf; inetdev; - priv = (struct netiucv_priv*)ndev->priv; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + ndev = cp->netdev; + priv = netdev_priv(ndev); dev = priv->dev; - - if (strncmp(name, ndev->name, count)) { - clist = &((*clist)->next); - continue; - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + if (strncmp(name, ndev->name, count)) + continue; + read_unlock_bh(&iucv_connection_rwlock); if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - PRINT_WARN( - "netiucv: net device %s active with peer %s\n", - ndev->name, priv->conn->userid); + PRINT_WARN("netiucv: net device %s active with peer " + "%s\n", ndev->name, priv->conn->userid); PRINT_WARN("netiucv: %s cannot be removed\n", - ndev->name); + ndev->name); IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); return -EBUSY; } @@ -2106,7 +2077,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) netiucv_unregister_device(dev); return count; } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + read_unlock_bh(&iucv_connection_rwlock); PRINT_WARN("netiucv: net device %s unknown\n", name); IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); return -EINVAL; @@ -2114,67 +2085,86 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) static DRIVER_ATTR(remove, 0200, NULL, remove_write); -static void -netiucv_banner(void) +static struct attribute * netiucv_drv_attrs[] = { + &driver_attr_connection.attr, + &driver_attr_remove.attr, + NULL, +}; + +static struct attribute_group netiucv_drv_attr_group = { + .attrs = netiucv_drv_attrs, +}; + +static void netiucv_banner(void) { PRINT_INFO("NETIUCV driver initialized\n"); } -static void __exit -netiucv_exit(void) +static void __exit netiucv_exit(void) { + struct iucv_connection *cp; + struct net_device *ndev; + struct netiucv_priv *priv; + struct device *dev; + IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - while (iucv_conns.iucv_connections) { - struct net_device *ndev = iucv_conns.iucv_connections->netdev; - struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; - struct device *dev = priv->dev; + while (!list_empty(&iucv_connection_list)) { + cp = list_entry(iucv_connection_list.next, + struct iucv_connection, list); + list_del(&cp->list); + ndev = cp->netdev; + priv = netdev_priv(ndev); + dev = priv->dev; unregister_netdev(ndev); netiucv_unregister_device(dev); } - driver_remove_file(&netiucv_driver, &driver_attr_connection); - driver_remove_file(&netiucv_driver, &driver_attr_remove); + sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); driver_unregister(&netiucv_driver); + iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); PRINT_INFO("NETIUCV driver unloaded\n"); return; } -static int __init -netiucv_init(void) +static int __init netiucv_init(void) { - int ret; + int rc; - ret = iucv_register_dbf_views(); - if (ret) { - PRINT_WARN("netiucv_init failed, " - "iucv_register_dbf_views rc = %d\n", ret); - return ret; - } + rc = iucv_register_dbf_views(); + if (rc) + goto out; + rc = iucv_register(&netiucv_handler, 1); + if (rc) + goto out_dbf; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - ret = driver_register(&netiucv_driver); - if (ret) { + rc = driver_register(&netiucv_driver); + if (rc) { PRINT_ERR("NETIUCV: failed to register driver.\n"); - IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret); - iucv_unregister_dbf_views(); - return ret; + IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); + goto out_iucv; } - /* Add entry for specifying connections. */ - ret = driver_create_file(&netiucv_driver, &driver_attr_connection); - if (!ret) { - ret = driver_create_file(&netiucv_driver, &driver_attr_remove); - netiucv_banner(); - rwlock_init(&iucv_conns.iucv_rwlock); - } else { - PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); - IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); - driver_unregister(&netiucv_driver); - iucv_unregister_dbf_views(); + rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); + if (rc) { + PRINT_ERR("NETIUCV: failed to add driver attributes.\n"); + IUCV_DBF_TEXT_(setup, 2, + "ret %d - netiucv_drv_attr_group\n", rc); + goto out_driver; } - return ret; + netiucv_banner(); + return rc; + +out_driver: + driver_unregister(&netiucv_driver); +out_iucv: + iucv_unregister(&netiucv_handler, 1); +out_dbf: + iucv_unregister_dbf_views(); +out: + return rc; } module_init(netiucv_init); diff --git a/trunk/drivers/s390/net/smsgiucv.c b/trunk/drivers/s390/net/smsgiucv.c index b8179c27ceb6..3ccca5871fdf 100644 --- a/trunk/drivers/s390/net/smsgiucv.c +++ b/trunk/drivers/s390/net/smsgiucv.c @@ -1,7 +1,7 @@ /* * IUCV special message driver * - * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * * This program is free software; you can redistribute it and/or modify @@ -23,10 +23,10 @@ #include #include #include +#include #include #include - -#include "iucv.h" +#include "smsgiucv.h" struct smsg_callback { struct list_head list; @@ -39,38 +39,46 @@ MODULE_AUTHOR ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)"); MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); -static iucv_handle_t smsg_handle; -static unsigned short smsg_pathid; +static struct iucv_path *smsg_path; + static DEFINE_SPINLOCK(smsg_list_lock); static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list); -static void -smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data) +static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); +static void smsg_message_pending(struct iucv_path *, struct iucv_message *); + +static struct iucv_handler smsg_handler = { + .path_pending = smsg_path_pending, + .message_pending = smsg_message_pending, +}; + +static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8], + u8 ipuser[16]) { + if (strncmp(ipvmid, "*MSG ", sizeof(ipvmid)) != 0) + return -EINVAL; + /* Path pending from *MSG. */ + return iucv_path_accept(path, &smsg_handler, "SMSGIUCV ", NULL); } - -static void -smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) +static void smsg_message_pending(struct iucv_path *path, + struct iucv_message *msg) { struct smsg_callback *cb; - unsigned char *msg; + unsigned char *buffer; unsigned char sender[9]; - unsigned short len; int rc, i; - len = eib->ln1msg2.ipbfln1f; - msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA); - if (!msg) { - iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls); + buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA); + if (!buffer) { + iucv_message_reject(path, msg); return; } - rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls, - msg, len, NULL, NULL, NULL); + rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL); if (rc == 0) { - msg[len] = 0; - EBCASC(msg, len); - memcpy(sender, msg, 8); + buffer[msg->length] = 0; + EBCASC(buffer, msg->length); + memcpy(sender, buffer, 8); sender[8] = 0; /* Remove trailing whitespace from the sender name. */ for (i = 7; i >= 0; i--) { @@ -80,27 +88,17 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) } spin_lock(&smsg_list_lock); list_for_each_entry(cb, &smsg_list, list) - if (strncmp(msg + 8, cb->prefix, cb->len) == 0) { - cb->callback(sender, msg + 8); + if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) { + cb->callback(sender, buffer + 8); break; } spin_unlock(&smsg_list_lock); } - kfree(msg); + kfree(buffer); } -static iucv_interrupt_ops_t smsg_ops = { - .ConnectionComplete = smsg_connection_complete, - .MessagePending = smsg_message_pending, -}; - -static struct device_driver smsg_driver = { - .name = "SMSGIUCV", - .bus = &iucv_bus, -}; - -int -smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) +int smsg_register_callback(char *prefix, + void (*callback)(char *from, char *str)) { struct smsg_callback *cb; @@ -110,18 +108,18 @@ smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) cb->prefix = prefix; cb->len = strlen(prefix); cb->callback = callback; - spin_lock(&smsg_list_lock); + spin_lock_bh(&smsg_list_lock); list_add_tail(&cb->list, &smsg_list); - spin_unlock(&smsg_list_lock); + spin_unlock_bh(&smsg_list_lock); return 0; } -void -smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) +void smsg_unregister_callback(char *prefix, + void (*callback)(char *from, char *str)) { struct smsg_callback *cb, *tmp; - spin_lock(&smsg_list_lock); + spin_lock_bh(&smsg_list_lock); cb = NULL; list_for_each_entry(tmp, &smsg_list, list) if (tmp->callback == callback && @@ -130,55 +128,58 @@ smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) list_del(&cb->list); break; } - spin_unlock(&smsg_list_lock); + spin_unlock_bh(&smsg_list_lock); kfree(cb); } -static void __exit -smsg_exit(void) +static struct device_driver smsg_driver = { + .name = "SMSGIUCV", + .bus = &iucv_bus, +}; + +static void __exit smsg_exit(void) { - if (smsg_handle > 0) { - cpcmd("SET SMSG OFF", NULL, 0, NULL); - iucv_sever(smsg_pathid, NULL); - iucv_unregister_program(smsg_handle); - driver_unregister(&smsg_driver); - } - return; + cpcmd("SET SMSG IUCV", NULL, 0, NULL); + iucv_unregister(&smsg_handler, 1); + driver_unregister(&smsg_driver); } -static int __init -smsg_init(void) +static int __init smsg_init(void) { - static unsigned char pgmmask[24] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; int rc; rc = driver_register(&smsg_driver); - if (rc != 0) { - printk(KERN_ERR "SMSGIUCV: failed to register driver.\n"); - return rc; - } - smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ", - pgmmask, &smsg_ops, NULL); - if (!smsg_handle) { + if (rc != 0) + goto out; + rc = iucv_register(&smsg_handler, 1); + if (rc) { printk(KERN_ERR "SMSGIUCV: failed to register to iucv"); - driver_unregister(&smsg_driver); - return -EIO; /* better errno ? */ + rc = -EIO; /* better errno ? */ + goto out_driver; + } + smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL); + if (!smsg_path) { + rc = -ENOMEM; + goto out_register; } - rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0, - NULL, NULL, smsg_handle, NULL); + rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", + NULL, NULL, NULL); if (rc) { printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG"); - iucv_unregister_program(smsg_handle); - driver_unregister(&smsg_driver); - smsg_handle = NULL; - return -EIO; + rc = -EIO; /* better errno ? */ + goto out_free; } cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; + +out_free: + iucv_path_free(smsg_path); +out_register: + iucv_unregister(&smsg_handler, 1); +out_driver: + driver_unregister(&smsg_driver); +out: + return rc; } module_init(smsg_init); diff --git a/trunk/drivers/scsi/NCR53C9x.c b/trunk/drivers/scsi/NCR53C9x.c index 3c912ee29da0..8b5334c56f0a 100644 --- a/trunk/drivers/scsi/NCR53C9x.c +++ b/trunk/drivers/scsi/NCR53C9x.c @@ -528,12 +528,16 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs) /* Allocate structure and insert basic data such as SCSI chip frequency * data and a pointer to the device */ -struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev) +struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev, + int hotplug) { struct NCR_ESP *esp, *elink; struct Scsi_Host *esp_host; - esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); + if (hotplug) + esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP)); + else + esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); if(!esp_host) panic("Cannot register ESP SCSI host"); esp = (struct NCR_ESP *) esp_host->hostdata; diff --git a/trunk/drivers/scsi/NCR53C9x.h b/trunk/drivers/scsi/NCR53C9x.h index 521e3f842cfd..d85cb73a9f69 100644 --- a/trunk/drivers/scsi/NCR53C9x.h +++ b/trunk/drivers/scsi/NCR53C9x.h @@ -652,7 +652,7 @@ extern int nesps, esps_in_use, esps_running; /* External functions */ extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs); -extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *); +extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int); extern void esp_deallocate(struct NCR_ESP *); extern void esp_release(void); extern void esp_initialize(struct NCR_ESP *); diff --git a/trunk/drivers/scsi/blz1230.c b/trunk/drivers/scsi/blz1230.c index 329a8f297b31..23f7c24ab809 100644 --- a/trunk/drivers/scsi/blz1230.c +++ b/trunk/drivers/scsi/blz1230.c @@ -121,7 +121,8 @@ int __init blz1230_esp_detect(struct scsi_host_template *tpnt) */ address = ZTWO_VADDR(board); eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR); - esp = esp_allocate(tpnt, (void *)board+REAL_BLZ1230_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR, + 0); esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); udelay(5); diff --git a/trunk/drivers/scsi/blz2060.c b/trunk/drivers/scsi/blz2060.c index b6c137b97350..b6203ec00961 100644 --- a/trunk/drivers/scsi/blz2060.c +++ b/trunk/drivers/scsi/blz2060.c @@ -100,7 +100,7 @@ int __init blz2060_esp_detect(struct scsi_host_template *tpnt) unsigned long board = z->resource.start; if (request_mem_region(board+BLZ2060_ESP_ADDR, sizeof(struct ESP_regs), "NCR53C9x")) { - esp = esp_allocate(tpnt, (void *)board+BLZ2060_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/trunk/drivers/scsi/cyberstorm.c b/trunk/drivers/scsi/cyberstorm.c index 7c7cfb54e897..c6b98a42e89d 100644 --- a/trunk/drivers/scsi/cyberstorm.c +++ b/trunk/drivers/scsi/cyberstorm.c @@ -126,7 +126,7 @@ int __init cyber_esp_detect(struct scsi_host_template *tpnt) sizeof(struct ESP_regs)); return 0; } - esp = esp_allocate(tpnt, (void *)board+CYBER_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/trunk/drivers/scsi/cyberstormII.c b/trunk/drivers/scsi/cyberstormII.c index d88cb9cf091e..e336e853e66f 100644 --- a/trunk/drivers/scsi/cyberstormII.c +++ b/trunk/drivers/scsi/cyberstormII.c @@ -98,7 +98,7 @@ int __init cyberII_esp_detect(struct scsi_host_template *tpnt) address = (unsigned long)ZTWO_VADDR(board); eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR); - esp = esp_allocate(tpnt, (void *)board+CYBERII_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0); esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); udelay(5); diff --git a/trunk/drivers/scsi/dec_esp.c b/trunk/drivers/scsi/dec_esp.c index c29ccbc44693..d42ad663ffee 100644 --- a/trunk/drivers/scsi/dec_esp.c +++ b/trunk/drivers/scsi/dec_esp.c @@ -18,7 +18,7 @@ * 20001005 - Initialization fixes for 2.4.0-test9 * Florian Lohoff * - * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki */ #include @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -42,7 +43,6 @@ #include #include #include -#include #define DEC_SCSI_SREG 0 #define DEC_SCSI_DMAREG 0x40000 @@ -98,51 +98,33 @@ static irqreturn_t scsi_dma_merr_int(int, void *); static irqreturn_t scsi_dma_err_int(int, void *); static irqreturn_t scsi_dma_int(int, void *); -static int dec_esp_detect(struct scsi_host_template * tpnt); - -static int dec_esp_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -static struct scsi_host_template driver_template = { - .proc_name = "dec_esp", - .proc_info = esp_proc_info, +static struct scsi_host_template dec_esp_template = { + .module = THIS_MODULE, .name = "NCR53C94", - .detect = dec_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = dec_esp_release, .info = esp_info, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .proc_info = esp_proc_info, + .proc_name = "dec_esp", .can_queue = 7, - .this_id = 7, .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, }; - -#include "scsi_module.c" +static struct NCR_ESP *dec_esp_platform; /***************************************************************** Detection */ -static int dec_esp_detect(struct scsi_host_template * tpnt) +static int dec_esp_platform_probe(void) { struct NCR_ESP *esp; - struct ConfigDev *esp_dev; - int slot; - unsigned long mem_start; + int err = 0; if (IOASIC) { - esp_dev = 0; - esp = esp_allocate(tpnt, (void *) esp_dev); + esp = esp_allocate(&dec_esp_template, NULL, 1); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; @@ -200,112 +182,175 @@ static int dec_esp_detect(struct scsi_host_template * tpnt) /* Check for differential SCSI-bus */ esp->diff = 0; + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, + "ncr53c94", esp->ehost); + if (err) + goto err_alloc; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], + scsi_dma_merr_int, IRQF_DISABLED, + "ncr53c94 error", esp->ehost); + if (err) + goto err_irq; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], + scsi_dma_err_int, IRQF_DISABLED, + "ncr53c94 overrun", esp->ehost); + if (err) + goto err_irq_merr; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int, + IRQF_DISABLED, "ncr53c94 dma", esp->ehost); + if (err) + goto err_irq_err; + esp_initialize(esp); - if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, - "ncr53c94", esp->ehost)) - goto err_dealloc; - if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], - scsi_dma_merr_int, IRQF_DISABLED, - "ncr53c94 error", esp->ehost)) - goto err_free_irq; - if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], - scsi_dma_err_int, IRQF_DISABLED, - "ncr53c94 overrun", esp->ehost)) - goto err_free_irq_merr; - if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], - scsi_dma_int, IRQF_DISABLED, - "ncr53c94 dma", esp->ehost)) - goto err_free_irq_err; + err = scsi_add_host(esp->ehost, NULL); + if (err) { + printk(KERN_ERR "ESP: Unable to register adapter\n"); + goto err_irq_dma; + } + + scsi_scan_host(esp->ehost); + dec_esp_platform = esp; } - if (TURBOCHANNEL) { - while ((slot = search_tc_card("PMAZ-AA")) >= 0) { - claim_tc_card(slot); - - esp_dev = 0; - esp = esp_allocate(tpnt, (void *) esp_dev); - - mem_start = get_tc_base_addr(slot); - - /* Store base addr into esp struct */ - esp->slot = CPHYSADDR(mem_start); - - esp->dregs = 0; - esp->eregs = (void *)CKSEG1ADDR(mem_start + - DEC_SCSI_SREG); - esp->do_pio_cmds = 1; - - /* Set the command buffer */ - esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer; - - /* get virtual dma address for command buffer */ - esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); - - esp->cfreq = get_tc_speed(); - - esp->irq = get_tc_irq_nr(slot); - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &pmaz_dma_init_read; - esp->dma_init_write = &pmaz_dma_init_write; - esp->dma_ints_off = &pmaz_dma_ints_off; - esp->dma_ints_on = &pmaz_dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &pmaz_dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = &pmaz_dma_drain; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_poll = 0; - esp->dma_reset = 0; - esp->dma_led_off = 0; - esp->dma_led_on = 0; - - esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; - esp->dma_mmu_get_scsi_sgl = 0; - esp->dma_mmu_release_scsi_one = 0; - esp->dma_mmu_release_scsi_sgl = 0; - esp->dma_advance_sg = 0; - - if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, - "PMAZ_AA", esp->ehost)) { - esp_deallocate(esp); - release_tc_card(slot); - continue; - } - esp->scsi_id = 7; - esp->diff = 0; - esp_initialize(esp); - } + return 0; + +err_irq_dma: + free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost); +err_irq_err: + free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost); +err_irq_merr: + free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost); +err_irq: + free_irq(esp->irq, esp->ehost); +err_alloc: + esp_deallocate(esp); + scsi_host_put(esp->ehost); + return err; +} + +static int __init dec_esp_probe(struct device *dev) +{ + struct NCR_ESP *esp; + resource_size_t start, len; + int err; + + esp = esp_allocate(&dec_esp_template, NULL, 1); + + dev_set_drvdata(dev, esp); + + start = to_tc_dev(dev)->resource.start; + len = to_tc_dev(dev)->resource.end - start + 1; + + if (!request_mem_region(start, len, dev->bus_id)) { + printk(KERN_ERR "%s: Unable to reserve MMIO resource\n", + dev->bus_id); + err = -EBUSY; + goto err_alloc; } - if(nesps) { - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; + /* Store base addr into esp struct. */ + esp->slot = start; + + esp->dregs = 0; + esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG); + esp->do_pio_cmds = 1; + + /* Set the command buffer. */ + esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer; + + /* Get virtual dma address for command buffer. */ + esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); + + esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus); + + esp->irq = to_tc_dev(dev)->interrupt; + + /* Required functions. */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &pmaz_dma_init_read; + esp->dma_init_write = &pmaz_dma_init_write; + esp->dma_ints_off = &pmaz_dma_ints_off; + esp->dma_ints_on = &pmaz_dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &pmaz_dma_setup; + + /* Optional functions. */ + esp->dma_barrier = 0; + esp->dma_drain = &pmaz_dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = 0; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = 0; + + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA", + esp->ehost); + if (err) { + printk(KERN_ERR "%s: Unable to get IRQ %d\n", + dev->bus_id, esp->irq); + goto err_resource; + } + + esp->scsi_id = 7; + esp->diff = 0; + esp_initialize(esp); + + err = scsi_add_host(esp->ehost, dev); + if (err) { + printk(KERN_ERR "%s: Unable to register adapter\n", + dev->bus_id); + goto err_irq; } + + scsi_scan_host(esp->ehost); + return 0; -err_free_irq_err: - free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int); -err_free_irq_merr: - free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int); -err_free_irq: - free_irq(esp->irq, esp_intr); -err_dealloc: +err_irq: + free_irq(esp->irq, esp->ehost); + +err_resource: + release_mem_region(start, len); + +err_alloc: esp_deallocate(esp); - return 0; + scsi_host_put(esp->ehost); + return err; +} + +static void __exit dec_esp_platform_remove(void) +{ + struct NCR_ESP *esp = dec_esp_platform; + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); + dec_esp_platform = NULL; } +static void __exit dec_esp_remove(struct device *dev) +{ + struct NCR_ESP *esp = dev_get_drvdata(dev); + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); +} + + /************************************************************* DMA Functions */ static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id) { @@ -576,3 +621,67 @@ static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp { sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); } + + +#ifdef CONFIG_TC +static int __init dec_esp_tc_probe(struct device *dev); +static int __exit dec_esp_tc_remove(struct device *dev); + +static const struct tc_device_id dec_esp_tc_table[] = { + { "DEC ", "PMAZ-AA " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dec_esp_tc_table); + +static struct tc_driver dec_esp_tc_driver = { + .id_table = dec_esp_tc_table, + .driver = { + .name = "dec_esp", + .bus = &tc_bus_type, + .probe = dec_esp_tc_probe, + .remove = __exit_p(dec_esp_tc_remove), + }, +}; + +static int __init dec_esp_tc_probe(struct device *dev) +{ + int status = dec_esp_probe(dev); + if (!status) + get_device(dev); + return status; +} + +static int __exit dec_esp_tc_remove(struct device *dev) +{ + put_device(dev); + dec_esp_remove(dev); + return 0; +} +#endif + +static int __init dec_esp_init(void) +{ + int status; + + status = tc_register_driver(&dec_esp_tc_driver); + if (!status) + dec_esp_platform_probe(); + + if (nesps) { + pr_info("ESP: Total of %d ESP hosts found, " + "%d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + } + + return status; +} + +static void __exit dec_esp_exit(void) +{ + dec_esp_platform_remove(); + tc_unregister_driver(&dec_esp_tc_driver); +} + + +module_init(dec_esp_init); +module_exit(dec_esp_exit); diff --git a/trunk/drivers/scsi/fastlane.c b/trunk/drivers/scsi/fastlane.c index 2a1c5c22b9e0..4266a2139b5f 100644 --- a/trunk/drivers/scsi/fastlane.c +++ b/trunk/drivers/scsi/fastlane.c @@ -142,7 +142,7 @@ int __init fastlane_esp_detect(struct scsi_host_template *tpnt) if (board < 0x1000000) { goto err_release; } - esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/trunk/drivers/scsi/iscsi_tcp.c b/trunk/drivers/scsi/iscsi_tcp.c index 437684084377..8f55e1431433 100644 --- a/trunk/drivers/scsi/iscsi_tcp.c +++ b/trunk/drivers/scsi/iscsi_tcp.c @@ -1375,7 +1375,7 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) } BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE); - if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) { + if (mtask->hdr->itt == RESERVED_ITT) { struct iscsi_session *session = conn->session; spin_lock_bh(&session->lock); diff --git a/trunk/drivers/scsi/jazz_esp.c b/trunk/drivers/scsi/jazz_esp.c index bfac4441d89f..19dd4b962e18 100644 --- a/trunk/drivers/scsi/jazz_esp.c +++ b/trunk/drivers/scsi/jazz_esp.c @@ -75,7 +75,7 @@ static int jazz_esp_detect(struct scsi_host_template *tpnt) */ if (1) { esp_dev = NULL; - esp = esp_allocate(tpnt, (void *) esp_dev); + esp = esp_allocate(tpnt, esp_dev, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/trunk/drivers/scsi/libiscsi.c b/trunk/drivers/scsi/libiscsi.c index d37048c96eab..7c75771c77ff 100644 --- a/trunk/drivers/scsi/libiscsi.c +++ b/trunk/drivers/scsi/libiscsi.c @@ -113,8 +113,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); - hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) | - (session->age << ISCSI_AGE_SHIFT); + hdr->itt = build_itt(ctask->itt, conn->id, session->age); hdr->data_length = cpu_to_be32(sc->request_bufflen); hdr->cmdsn = cpu_to_be32(session->cmdsn); session->cmdsn++; @@ -270,7 +269,7 @@ static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, goto out; } - senselen = be16_to_cpu(*(uint16_t *)data); + senselen = be16_to_cpu(*(__be16 *)data); if (datalen < senselen) goto invalid_datalen; @@ -338,7 +337,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); - itt = rejected_pdu.itt & ISCSI_ITT_MASK; + itt = get_itt(rejected_pdu.itt); printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " "due to DataDigest error.\n", itt, rejected_pdu.opcode); @@ -367,10 +366,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, struct iscsi_mgmt_task *mtask; uint32_t itt; - if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) - itt = hdr->itt & ISCSI_ITT_MASK; + if (hdr->itt != RESERVED_ITT) + itt = get_itt(hdr->itt); else - itt = hdr->itt; + itt = ~0U; if (itt < session->cmds_max) { ctask = session->cmds[itt]; @@ -440,7 +439,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, iscsi_tmf_rsp(conn, hdr); break; case ISCSI_OP_NOOP_IN: - if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) { + if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { rc = ISCSI_ERR_PROTO; break; } @@ -457,7 +456,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, rc = ISCSI_ERR_BAD_OPCODE; break; } - } else if (itt == ISCSI_RESERVED_TAG) { + } else if (itt == ~0U) { rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)hdr); if (rc) @@ -470,7 +469,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, break; } - if (hdr->ttt == ISCSI_RESERVED_TAG) + if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) break; if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0)) @@ -516,24 +515,24 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, struct iscsi_cmd_task *ctask; uint32_t itt; - if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { - if ((hdr->itt & ISCSI_AGE_MASK) != + if (hdr->itt != RESERVED_ITT) { + if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != (session->age << ISCSI_AGE_SHIFT)) { printk(KERN_ERR "iscsi: received itt %x expected " - "session age (%x)\n", hdr->itt, + "session age (%x)\n", (__force u32)hdr->itt, session->age & ISCSI_AGE_MASK); return ISCSI_ERR_BAD_ITT; } - if ((hdr->itt & ISCSI_CID_MASK) != + if (((__force u32)hdr->itt & ISCSI_CID_MASK) != (conn->id << ISCSI_CID_SHIFT)) { printk(KERN_ERR "iscsi: received itt %x, expected " - "CID (%x)\n", hdr->itt, conn->id); + "CID (%x)\n", (__force u32)hdr->itt, conn->id); return ISCSI_ERR_BAD_ITT; } - itt = hdr->itt & ISCSI_ITT_MASK; + itt = get_itt(hdr->itt); } else - itt = hdr->itt; + itt = ~0U; if (itt < session->cmds_max) { ctask = session->cmds[itt]; @@ -896,9 +895,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, /* * pre-format CmdSN for outgoing PDU. */ - if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { - hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) | - (session->age << ISCSI_AGE_SHIFT); + if (hdr->itt != RESERVED_ITT) { + hdr->itt = build_itt(mtask->itt, conn->id, session->age); nop->cmdsn = cpu_to_be32(session->cmdsn); if (conn->c_stage == ISCSI_CONN_STARTED && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) @@ -1064,7 +1062,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, spin_lock_bh(&session->lock); ctask->mtask = (struct iscsi_mgmt_task *) - session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) - + session->mgmt_cmds[get_itt(hdr->itt) - ISCSI_MGMT_ITT_OFFSET]; if (conn->tmabort_state == TMABORT_INITIAL) { diff --git a/trunk/drivers/scsi/mac_esp.c b/trunk/drivers/scsi/mac_esp.c index 3586fac9be9a..bcb49021b7e2 100644 --- a/trunk/drivers/scsi/mac_esp.c +++ b/trunk/drivers/scsi/mac_esp.c @@ -351,7 +351,7 @@ int mac_esp_detect(struct scsi_host_template * tpnt) for (chipnum = 0; chipnum < chipspresent; chipnum ++) { struct NCR_ESP * esp; - esp = esp_allocate(tpnt, (void *) NULL); + esp = esp_allocate(tpnt, NULL, 0); esp->eregs = (struct ESP_regs *) get_base(chipnum); esp->dma_irq_p = &esp_dafb_dma_irq_p; diff --git a/trunk/drivers/scsi/mca_53c9x.c b/trunk/drivers/scsi/mca_53c9x.c index 998a8bbc1a4b..d693d0f21395 100644 --- a/trunk/drivers/scsi/mca_53c9x.c +++ b/trunk/drivers/scsi/mca_53c9x.c @@ -122,7 +122,7 @@ static int mca_esp_detect(struct scsi_host_template *tpnt) if ((slot = mca_find_adapter(*id_to_check, 0)) != MCA_NOTFOUND) { - esp = esp_allocate(tpnt, (void *) NULL); + esp = esp_allocate(tpnt, NULL, 0); pos[0] = mca_read_stored_pos(slot, 2); pos[1] = mca_read_stored_pos(slot, 3); diff --git a/trunk/drivers/scsi/oktagon_esp.c b/trunk/drivers/scsi/oktagon_esp.c index c116a6ae3c54..26a6d55faf3e 100644 --- a/trunk/drivers/scsi/oktagon_esp.c +++ b/trunk/drivers/scsi/oktagon_esp.c @@ -133,7 +133,7 @@ int oktagon_esp_detect(struct scsi_host_template *tpnt) eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR); /* This line was 5 lines lower */ - esp = esp_allocate(tpnt, (void *)board+OKTAGON_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0); /* we have to shift the registers only one bit for oktagon */ esp->shift = 1; diff --git a/trunk/drivers/scsi/osst.c b/trunk/drivers/scsi/osst.c index 7d2311067903..bd6bbf61adb8 100644 --- a/trunk/drivers/scsi/osst.c +++ b/trunk/drivers/scsi/osst.c @@ -521,10 +521,10 @@ static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_ break; default: ; /* probably FILL */ } - aux->filemark_cnt = ntohl(STp->filemark_cnt); - aux->phys_fm = ntohl(0xffffffff); - aux->last_mark_ppos = ntohl(STp->last_mark_ppos); - aux->last_mark_lbn = ntohl(STp->last_mark_lbn); + aux->filemark_cnt = htonl(STp->filemark_cnt); + aux->phys_fm = htonl(0xffffffff); + aux->last_mark_ppos = htonl(STp->last_mark_ppos); + aux->last_mark_lbn = htonl(STp->last_mark_lbn); } /* diff --git a/trunk/drivers/scsi/osst.h b/trunk/drivers/scsi/osst.h index 1e426f5d0ed8..2cc7b5a1606a 100644 --- a/trunk/drivers/scsi/osst.h +++ b/trunk/drivers/scsi/osst.h @@ -288,11 +288,11 @@ typedef struct { #else #error "Please fix " #endif - u16 max_speed; /* Maximum speed supported in KBps */ + __be16 max_speed; /* Maximum speed supported in KBps */ u8 reserved10, reserved11; - u16 ctl; /* Continuous Transfer Limit in blocks */ - u16 speed; /* Current Speed, in KBps */ - u16 buffer_size; /* Buffer Size, in 512 bytes */ + __be16 ctl; /* Continuous Transfer Limit in blocks */ + __be16 speed; /* Current Speed, in KBps */ + __be16 buffer_size; /* Buffer Size, in 512 bytes */ u8 reserved18, reserved19; } osst_capabilities_page_t; @@ -352,8 +352,8 @@ typedef struct { u8 reserved2; u8 density; u8 reserved3,reserved4; - u16 segtrk; - u16 trks; + __be16 segtrk; + __be16 trks; u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10; } osst_tape_paramtr_page_t; @@ -369,18 +369,18 @@ typedef struct { typedef struct os_partition_s { __u8 partition_num; __u8 par_desc_ver; - __u16 wrt_pass_cntr; - __u32 first_frame_ppos; - __u32 last_frame_ppos; - __u32 eod_frame_ppos; + __be16 wrt_pass_cntr; + __be32 first_frame_ppos; + __be32 last_frame_ppos; + __be32 eod_frame_ppos; } os_partition_t; /* * DAT entry */ typedef struct os_dat_entry_s { - __u32 blk_sz; - __u16 blk_cnt; + __be32 blk_sz; + __be16 blk_cnt; __u8 flags; __u8 reserved; } os_dat_entry_t; @@ -412,23 +412,23 @@ typedef struct os_dat_s { * AUX */ typedef struct os_aux_s { - __u32 format_id; /* hardware compability AUX is based on */ + __be32 format_id; /* hardware compability AUX is based on */ char application_sig[4]; /* driver used to write this media */ - __u32 hdwr; /* reserved */ - __u32 update_frame_cntr; /* for configuration frame */ + __be32 hdwr; /* reserved */ + __be32 update_frame_cntr; /* for configuration frame */ __u8 frame_type; __u8 frame_type_reserved; __u8 reserved_18_19[2]; os_partition_t partition; __u8 reserved_36_43[8]; - __u32 frame_seq_num; - __u32 logical_blk_num_high; - __u32 logical_blk_num; + __be32 frame_seq_num; + __be32 logical_blk_num_high; + __be32 logical_blk_num; os_dat_t dat; __u8 reserved188_191[4]; - __u32 filemark_cnt; - __u32 phys_fm; - __u32 last_mark_ppos; + __be32 filemark_cnt; + __be32 phys_fm; + __be32 last_mark_ppos; __u8 reserved204_223[20]; /* @@ -436,8 +436,8 @@ typedef struct os_aux_s { * * Linux specific fields: */ - __u32 next_mark_ppos; /* when known, points to next marker */ - __u32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ + __be32 next_mark_ppos; /* when known, points to next marker */ + __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ __u8 linux_specific[24]; __u8 reserved_256_511[256]; @@ -450,19 +450,19 @@ typedef struct os_fm_tab_s { __u8 reserved_1; __u8 fm_tab_ent_sz; __u8 reserved_3; - __u16 fm_tab_ent_cnt; + __be16 fm_tab_ent_cnt; __u8 reserved6_15[10]; - __u32 fm_tab_ent[OS_FM_TAB_MAX]; + __be32 fm_tab_ent[OS_FM_TAB_MAX]; } os_fm_tab_t; typedef struct os_ext_trk_ey_s { __u8 et_part_num; __u8 fmt; - __u16 fm_tab_off; + __be16 fm_tab_off; __u8 reserved4_7[4]; - __u32 last_hlb_hi; - __u32 last_hlb; - __u32 last_pp; + __be32 last_hlb_hi; + __be32 last_hlb; + __be32 last_pp; __u8 reserved20_31[12]; } os_ext_trk_ey_t; @@ -479,17 +479,17 @@ typedef struct os_header_s { char ident_str[8]; __u8 major_rev; __u8 minor_rev; - __u16 ext_trk_tb_off; + __be16 ext_trk_tb_off; __u8 reserved12_15[4]; __u8 pt_par_num; __u8 pt_reserved1_3[3]; os_partition_t partition[16]; - __u32 cfg_col_width; - __u32 dat_col_width; - __u32 qfa_col_width; + __be32 cfg_col_width; + __be32 dat_col_width; + __be32 qfa_col_width; __u8 cartridge[16]; __u8 reserved304_511[208]; - __u32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ + __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ os_ext_trk_tb_t ext_track_tb; __u8 reserved17272_17735[464]; os_fm_tab_t dat_fm_tab; diff --git a/trunk/drivers/scsi/sun3x_esp.c b/trunk/drivers/scsi/sun3x_esp.c index 6b60536ac92b..80fb3f88af2e 100644 --- a/trunk/drivers/scsi/sun3x_esp.c +++ b/trunk/drivers/scsi/sun3x_esp.c @@ -53,7 +53,7 @@ int sun3x_esp_detect(struct scsi_host_template *tpnt) struct ConfigDev *esp_dev; esp_dev = 0; - esp = esp_allocate(tpnt, (void *) esp_dev); + esp = esp_allocate(tpnt, esp_dev, 0); /* Do command transfer with DMA */ esp->do_pio_cmds = 0; diff --git a/trunk/drivers/serial/uartlite.c b/trunk/drivers/serial/uartlite.c index db8607e3d531..f5051cf1a0c8 100644 --- a/trunk/drivers/serial/uartlite.c +++ b/trunk/drivers/serial/uartlite.c @@ -256,7 +256,7 @@ static void ulite_release_port(struct uart_port *port) { release_mem_region(port->mapbase, ULITE_REGION); iounmap(port->membase); - port->membase = 0; + port->membase = NULL; } static int ulite_request_port(struct uart_port *port) @@ -438,7 +438,7 @@ static int __devinit ulite_probe(struct platform_device *pdev) port->iotype = UPIO_MEM; port->iobase = 1; /* mark port in use */ port->mapbase = res->start; - port->membase = 0; + port->membase = NULL; port->ops = &ulite_ops; port->irq = res2->start; port->flags = UPF_BOOT_AUTOCONF; @@ -462,7 +462,7 @@ static int ulite_remove(struct platform_device *pdev) uart_remove_one_port(&ulite_uart_driver, port); /* mark port as free */ - port->membase = 0; + port->membase = NULL; return 0; } diff --git a/trunk/drivers/tc/Makefile b/trunk/drivers/tc/Makefile index 83b5bd75ce26..967342692211 100644 --- a/trunk/drivers/tc/Makefile +++ b/trunk/drivers/tc/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-$(CONFIG_TC) += tc.o +obj-$(CONFIG_TC) += tc.o tc-driver.o obj-$(CONFIG_ZS) += zs.o obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o diff --git a/trunk/drivers/tc/tc-driver.c b/trunk/drivers/tc/tc-driver.c new file mode 100644 index 000000000000..16b5bae63c74 --- /dev/null +++ b/trunk/drivers/tc/tc-driver.c @@ -0,0 +1,110 @@ +/* + * TURBOchannel driver services. + * + * Copyright (c) 2005 James Simmons + * Copyright (c) 2006 Maciej W. Rozycki + * + * Loosely based on drivers/dio/dio-driver.c and + * drivers/pci/pci-driver.c. + * + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. + */ + +#include +#include +#include + +/** + * tc_register_driver - register a new TC driver + * @drv: the driver structure to register + * + * Adds the driver structure to the list of registered drivers + * Returns a negative value on error, otherwise 0. + * If no error occurred, the driver remains registered even if + * no device was claimed during registration. + */ +int tc_register_driver(struct tc_driver *tdrv) +{ + return driver_register(&tdrv->driver); +} +EXPORT_SYMBOL(tc_register_driver); + +/** + * tc_unregister_driver - unregister a TC driver + * @drv: the driver structure to unregister + * + * Deletes the driver structure from the list of registered TC drivers, + * gives it a chance to clean up by calling its remove() function for + * each device it was responsible for, and marks those devices as + * driverless. + */ +void tc_unregister_driver(struct tc_driver *tdrv) +{ + driver_unregister(&tdrv->driver); +} +EXPORT_SYMBOL(tc_unregister_driver); + +/** + * tc_match_device - tell if a TC device structure has a matching + * TC device ID structure + * @tdrv: the TC driver to earch for matching TC device ID strings + * @tdev: the TC device structure to match against + * + * Used by a driver to check whether a TC device present in the + * system is in its list of supported devices. Returns the matching + * tc_device_id structure or %NULL if there is no match. + */ +const struct tc_device_id *tc_match_device(struct tc_driver *tdrv, + struct tc_dev *tdev) +{ + const struct tc_device_id *id = tdrv->id_table; + + if (id) { + while (id->name[0] || id->vendor[0]) { + if (strcmp(tdev->name, id->name) == 0 && + strcmp(tdev->vendor, id->vendor) == 0) + return id; + id++; + } + } + return NULL; +} +EXPORT_SYMBOL(tc_match_device); + +/** + * tc_bus_match - Tell if a device structure has a matching + * TC device ID structure + * @dev: the device structure to match against + * @drv: the device driver to search for matching TC device ID strings + * + * Used by a driver to check whether a TC device present in the + * system is in its list of supported devices. Returns 1 if there + * is a match or 0 otherwise. + */ +static int tc_bus_match(struct device *dev, struct device_driver *drv) +{ + struct tc_dev *tdev = to_tc_dev(dev); + struct tc_driver *tdrv = to_tc_driver(drv); + const struct tc_device_id *id; + + id = tc_match_device(tdrv, tdev); + if (id) + return 1; + + return 0; +} + +struct bus_type tc_bus_type = { + .name = "tc", + .match = tc_bus_match, +}; +EXPORT_SYMBOL(tc_bus_type); + +static int __init tc_driver_init(void) +{ + return bus_register(&tc_bus_type); +} + +postcore_initcall(tc_driver_init); diff --git a/trunk/drivers/tc/tc.c b/trunk/drivers/tc/tc.c index 4a51e56f85b6..f77f62a4b325 100644 --- a/trunk/drivers/tc/tc.c +++ b/trunk/drivers/tc/tc.c @@ -1,254 +1,193 @@ /* - * tc-init: We assume the TURBOchannel to be up and running so - * just probe for Modules and fill in the global data structure - * tc_bus. + * TURBOchannel bus services. * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Copyright (c) Harald Koerfgen, 1998 + * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons * - * Copyright (c) Harald Koerfgen, 1998 - * Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. */ +#include +#include #include +#include #include +#include #include #include +#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -slot_info tc_bus[MAX_SLOT]; -static int num_tcslots; -static tcinfo *info; +static struct tc_bus tc_bus = { + .name = "TURBOchannel", +}; /* - * Interface to the world. Read comment in include/asm-mips/tc.h. + * Probing for TURBOchannel modules. */ - -int search_tc_card(const char *name) -{ - int slot; - slot_info *sip; - - for (slot = 0; slot < num_tcslots; slot++) { - sip = &tc_bus[slot]; - if ((sip->flags & FREE) && - (strncmp(sip->name, name, strlen(name)) == 0)) { - return slot; - } - } - - return -ENODEV; -} - -void claim_tc_card(int slot) -{ - if (tc_bus[slot].flags & IN_USE) { - printk("claim_tc_card: attempting to claim a card already in use\n"); - return; - } - tc_bus[slot].flags &= ~FREE; - tc_bus[slot].flags |= IN_USE; -} - -void release_tc_card(int slot) +static void __init tc_bus_add_devices(struct tc_bus *tbus) { - if (tc_bus[slot].flags & FREE) { - printk("release_tc_card: " - "attempting to release a card already free\n"); - return; - } - tc_bus[slot].flags &= ~IN_USE; - tc_bus[slot].flags |= FREE; -} - -unsigned long get_tc_base_addr(int slot) -{ - return tc_bus[slot].base_addr; -} - -unsigned long get_tc_irq_nr(int slot) -{ - return tc_bus[slot].interrupt; -} - -unsigned long get_tc_speed(void) -{ - return 100000 * (10000 / (unsigned long)info->clk_period); -} - -/* - * Probing for TURBOchannel modules - */ -static void __init tc_probe(unsigned long startaddr, unsigned long size, - int slots) -{ - unsigned long slotaddr; + resource_size_t slotsize = tbus->info.slot_size << 20; + resource_size_t extslotsize = tbus->ext_slot_size; + resource_size_t slotaddr; + resource_size_t extslotaddr; + resource_size_t devsize; + void __iomem *module; + struct tc_dev *tdev; int i, slot, err; - long offset; u8 pattern[4]; - volatile u8 *module; + long offset; - for (slot = 0; slot < slots; slot++) { - slotaddr = startaddr + slot * size; - module = ioremap_nocache(slotaddr, size); + for (slot = 0; slot < tbus->num_tcslots; slot++) { + slotaddr = tbus->slot_base + slot * slotsize; + extslotaddr = tbus->ext_slot_base + slot * extslotsize; + module = ioremap_nocache(slotaddr, slotsize); BUG_ON(!module); - offset = OLDCARD; + offset = TC_OLDCARD; err = 0; - err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0); - err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1); - err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2); - err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3); - if (err) { - iounmap(module); - continue; - } + err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0); + err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1); + err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2); + err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3); + if (err) + goto out_err; if (pattern[0] != 0x55 || pattern[1] != 0x00 || pattern[2] != 0xaa || pattern[3] != 0xff) { - offset = NEWCARD; + offset = TC_NEWCARD; err = 0; - err |= get_dbe(pattern[0], module + TC_PATTERN0); - err |= get_dbe(pattern[1], module + TC_PATTERN1); - err |= get_dbe(pattern[2], module + TC_PATTERN2); - err |= get_dbe(pattern[3], module + TC_PATTERN3); - if (err) { - iounmap(module); - continue; - } + err |= tc_preadb(pattern + 0, + module + offset + TC_PATTERN0); + err |= tc_preadb(pattern + 1, + module + offset + TC_PATTERN1); + err |= tc_preadb(pattern + 2, + module + offset + TC_PATTERN2); + err |= tc_preadb(pattern + 3, + module + offset + TC_PATTERN3); + if (err) + goto out_err; } if (pattern[0] != 0x55 || pattern[1] != 0x00 || - pattern[2] != 0xaa || pattern[3] != 0xff) { - iounmap(module); - continue; + pattern[2] != 0xaa || pattern[3] != 0xff) + goto out_err; + + /* Found a board, allocate it an entry in the list */ + tdev = kzalloc(sizeof(*tdev), GFP_KERNEL); + if (!tdev) { + printk(KERN_ERR "tc%x: unable to allocate tc_dev\n", + slot); + goto out_err; } + sprintf(tdev->dev.bus_id, "tc%x", slot); + tdev->bus = tbus; + tdev->dev.parent = &tbus->dev; + tdev->dev.bus = &tc_bus_type; + tdev->slot = slot; - tc_bus[slot].base_addr = slotaddr; for (i = 0; i < 8; i++) { - tc_bus[slot].firmware[i] = - module[TC_FIRM_VER + offset + 4 * i]; - tc_bus[slot].vendor[i] = - module[TC_VENDOR + offset + 4 * i]; - tc_bus[slot].name[i] = - module[TC_MODULE + offset + 4 * i]; + tdev->firmware[i] = + readb(module + offset + TC_FIRM_VER + 4 * i); + tdev->vendor[i] = + readb(module + offset + TC_VENDOR + 4 * i); + tdev->name[i] = + readb(module + offset + TC_MODULE + 4 * i); } - tc_bus[slot].firmware[8] = 0; - tc_bus[slot].vendor[8] = 0; - tc_bus[slot].name[8] = 0; - /* - * Looks unneccesary, but we may change - * TC? in the future - */ - switch (slot) { - case 0: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0]; - break; - case 1: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1]; - break; - case 2: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2]; - break; - /* - * Yuck! DS5000/200 onboard devices - */ - case 5: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5]; - break; - case 6: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6]; - break; - default: - tc_bus[slot].interrupt = -1; - break; + tdev->firmware[8] = 0; + tdev->vendor[8] = 0; + tdev->name[8] = 0; + + pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor, + tdev->name, tdev->firmware); + + devsize = readb(module + offset + TC_SLOT_SIZE); + devsize <<= 22; + if (devsize <= slotsize) { + tdev->resource.start = slotaddr; + tdev->resource.end = slotaddr + devsize - 1; + } else if (devsize <= extslotsize) { + tdev->resource.start = extslotaddr; + tdev->resource.end = extslotaddr + devsize - 1; + } else { + printk(KERN_ERR "%s: Cannot provide slot space " + "(%dMiB required, up to %dMiB supported)\n", + tdev->dev.bus_id, devsize >> 20, + max(slotsize, extslotsize) >> 20); + kfree(tdev); + goto out_err; } + tdev->resource.name = tdev->name; + tdev->resource.flags = IORESOURCE_MEM; + + tc_device_get_irq(tdev); + device_register(&tdev->dev); + list_add_tail(&tdev->node, &tbus->devices); + +out_err: iounmap(module); } } /* - * the main entry + * The main entry. */ static int __init tc_init(void) { - int tc_clock; - int i; - unsigned long slot0addr; - unsigned long slot_size; - - if (!TURBOCHANNEL) + /* Initialize the TURBOchannel bus */ + if (tc_bus_get_info(&tc_bus)) return 0; - for (i = 0; i < MAX_SLOT; i++) { - tc_bus[i].base_addr = 0; - tc_bus[i].name[0] = 0; - tc_bus[i].vendor[0] = 0; - tc_bus[i].firmware[0] = 0; - tc_bus[i].interrupt = -1; - tc_bus[i].flags = FREE; - } - - info = rex_gettcinfo(); - slot0addr = CPHYSADDR((long)rex_slot_address(0)); - - switch (mips_machtype) { - case MACH_DS5000_200: - num_tcslots = 7; - break; - case MACH_DS5000_1XX: - case MACH_DS5000_2X0: - case MACH_DS5900: - num_tcslots = 3; - break; - case MACH_DS5000_XX: - default: - num_tcslots = 2; - break; - } - - tc_clock = 10000 / info->clk_period; - - if (info->slot_size && slot0addr) { - pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n", - info->revision, tc_clock / 10, tc_clock % 10, - info->parity ? "" : "out"); - - slot_size = info->slot_size << 20; - - tc_probe(slot0addr, slot_size, num_tcslots); - - for (i = 0; i < num_tcslots; i++) { - if (!tc_bus[i].base_addr) - continue; - pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor, - tc_bus[i].name, tc_bus[i].firmware); + INIT_LIST_HEAD(&tc_bus.devices); + strcpy(tc_bus.dev.bus_id, "tc"); + device_register(&tc_bus.dev); + + if (tc_bus.info.slot_size) { + unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000; + + pr_info("tc: TURBOchannel rev. %d at %d.%d MHz " + "(with%s parity)\n", tc_bus.info.revision, + tc_clock / 10, tc_clock % 10, + tc_bus.info.parity ? "" : "out"); + + tc_bus.resource[0].start = tc_bus.slot_base; + tc_bus.resource[0].end = tc_bus.slot_base + + (tc_bus.info.slot_size << 20) * + tc_bus.num_tcslots - 1; + tc_bus.resource[0].name = tc_bus.name; + tc_bus.resource[0].flags = IORESOURCE_MEM; + if (request_resource(&iomem_resource, + &tc_bus.resource[0]) < 0) { + printk(KERN_ERR "tc: Cannot reserve resource\n"); + return 0; + } + if (tc_bus.ext_slot_size) { + tc_bus.resource[1].start = tc_bus.ext_slot_base; + tc_bus.resource[1].end = tc_bus.ext_slot_base + + tc_bus.ext_slot_size * + tc_bus.num_tcslots - 1; + tc_bus.resource[1].name = tc_bus.name; + tc_bus.resource[1].flags = IORESOURCE_MEM; + if (request_resource(&iomem_resource, + &tc_bus.resource[1]) < 0) { + printk(KERN_ERR + "tc: Cannot reserve resource\n"); + release_resource(&tc_bus.resource[0]); + return 0; + } } + + tc_bus_add_devices(&tc_bus); } return 0; } subsys_initcall(tc_init); - -EXPORT_SYMBOL(search_tc_card); -EXPORT_SYMBOL(claim_tc_card); -EXPORT_SYMBOL(release_tc_card); -EXPORT_SYMBOL(get_tc_base_addr); -EXPORT_SYMBOL(get_tc_irq_nr); -EXPORT_SYMBOL(get_tc_speed); diff --git a/trunk/drivers/usb/host/ehci-ps3.c b/trunk/drivers/usb/host/ehci-ps3.c index 371f194a9d39..4d781a2a9807 100644 --- a/trunk/drivers/usb/host/ehci-ps3.c +++ b/trunk/drivers/usb/host/ehci-ps3.c @@ -104,7 +104,7 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, __LINE__, dev->m_region->lpar_addr); - result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", diff --git a/trunk/drivers/usb/host/ehci.h b/trunk/drivers/usb/host/ehci.h index ec0da0343be4..46fa57a520d0 100644 --- a/trunk/drivers/usb/host/ehci.h +++ b/trunk/drivers/usb/host/ehci.h @@ -677,10 +677,10 @@ static inline unsigned int ehci_readl (const struct ehci_hcd *ehci, { #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO return ehci_big_endian_mmio(ehci) ? - readl_be((__force u32 *)regs) : - readl((__force u32 *)regs); + readl_be(regs) : + readl(regs); #else - return readl((__force u32 *)regs); + return readl(regs); #endif } @@ -689,10 +689,10 @@ static inline void ehci_writel (const struct ehci_hcd *ehci, { #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO ehci_big_endian_mmio(ehci) ? - writel_be(val, (__force u32 *)regs) : - writel(val, (__force u32 *)regs); + writel_be(val, regs) : + writel(val, regs); #else - writel(val, (__force u32 *)regs); + writel(val, regs); #endif } diff --git a/trunk/drivers/usb/host/ohci-ps3.c b/trunk/drivers/usb/host/ohci-ps3.c index 69d948b4a701..62283a3926de 100644 --- a/trunk/drivers/usb/host/ohci-ps3.c +++ b/trunk/drivers/usb/host/ohci-ps3.c @@ -107,7 +107,7 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, __LINE__, dev->m_region->lpar_addr); - result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", diff --git a/trunk/drivers/usb/host/ohci.h b/trunk/drivers/usb/host/ohci.h index 0dafcda37291..c2b5ecfe5e9f 100644 --- a/trunk/drivers/usb/host/ohci.h +++ b/trunk/drivers/usb/host/ohci.h @@ -507,10 +507,10 @@ static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, { #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO return big_endian_mmio(ohci) ? - readl_be ((__force u32 *)regs) : - readl ((__force u32 *)regs); + readl_be (regs) : + readl (regs); #else - return readl ((__force u32 *)regs); + return readl (regs); #endif } @@ -519,10 +519,10 @@ static inline void _ohci_writel (const struct ohci_hcd *ohci, { #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO big_endian_mmio(ohci) ? - writel_be (val, (__force u32 *)regs) : - writel (val, (__force u32 *)regs); + writel_be (val, regs) : + writel (val, regs); #else - writel (val, (__force u32 *)regs); + writel (val, regs); #endif } diff --git a/trunk/drivers/usb/net/gl620a.c b/trunk/drivers/usb/net/gl620a.c index a6f0f4d934df..31e5fe363fdc 100644 --- a/trunk/drivers/usb/net/gl620a.c +++ b/trunk/drivers/usb/net/gl620a.c @@ -70,12 +70,12 @@ (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) struct gl_packet { - u32 packet_length; + __le32 packet_length; char packet_data [1]; }; struct gl_header { - u32 packet_count; + __le32 packet_count; struct gl_packet packets; }; @@ -85,15 +85,14 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) struct gl_packet *packet; struct sk_buff *gl_skb; u32 size; + u32 count; header = (struct gl_header *) skb->data; // get the packet count of the received skb - le32_to_cpus(&header->packet_count); - if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS) - || (header->packet_count < 0)) { - dbg("genelink: invalid received packet count %d", - header->packet_count); + count = le32_to_cpu(header->packet_count); + if (count > GL_MAX_TRANSMIT_PACKETS) { + dbg("genelink: invalid received packet count %u", count); return 0; } @@ -103,7 +102,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) // decrement the length for the packet count size 4 bytes skb_pull(skb, 4); - while (header->packet_count > 1) { + while (count > 1) { // get the packet length size = le32_to_cpu(packet->packet_length); @@ -124,9 +123,8 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } // advance to the next packet - packet = (struct gl_packet *) - &packet->packet_data [size]; - header->packet_count--; + packet = (struct gl_packet *)&packet->packet_data[size]; + count--; // shift the data pointer to the next gl_packet skb_pull(skb, size + 4); @@ -149,8 +147,8 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) int length = skb->len; int headroom = skb_headroom(skb); int tailroom = skb_tailroom(skb); - u32 *packet_count; - u32 *packet_len; + __le32 *packet_count; + __le32 *packet_len; // FIXME: magic numbers, bleech padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; @@ -172,7 +170,7 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) } // attach the packet count to the header - packet_count = (u32 *) skb_push(skb, (4 + 4*1)); + packet_count = (__le32 *) skb_push(skb, (4 + 4*1)); packet_len = packet_count + 1; *packet_count = cpu_to_le32(1); diff --git a/trunk/drivers/usb/serial/cp2101.c b/trunk/drivers/usb/serial/cp2101.c index 06b4fffc189c..3ec24870bca9 100644 --- a/trunk/drivers/usb/serial/cp2101.c +++ b/trunk/drivers/usb/serial/cp2101.c @@ -170,13 +170,13 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; - u32 *buf; + __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ length = (((size - 1) | 3) + 1)/4; - buf = kcalloc(length, sizeof(u32), GFP_KERNEL); + buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); return -ENOMEM; @@ -216,13 +216,13 @@ static int cp2101_set_config(struct usb_serial_port* port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; - u32 *buf; + __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ length = (((size - 1) | 3) + 1)/4; - buf = kmalloc(length * sizeof(u32), GFP_KERNEL); + buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); diff --git a/trunk/drivers/video/Kconfig b/trunk/drivers/video/Kconfig index 4e83f01e894e..45fe65d8d7a0 100644 --- a/trunk/drivers/video/Kconfig +++ b/trunk/drivers/video/Kconfig @@ -1444,8 +1444,8 @@ config FB_PMAG_AA used mainly in the MIPS-based DECstation series. config FB_PMAG_BA - bool "PMAG-BA TURBOchannel framebuffer support" - depends on (FB = y) && TC + tristate "PMAG-BA TURBOchannel framebuffer support" + depends on FB && TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1454,8 +1454,8 @@ config FB_PMAG_BA used mainly in the MIPS-based DECstation series. config FB_PMAGB_B - bool "PMAGB-B TURBOchannel framebuffer support" - depends on (FB = y) && TC + tristate "PMAGB-B TURBOchannel framebuffer support" + depends on TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/trunk/drivers/video/pmag-ba-fb.c b/trunk/drivers/video/pmag-ba-fb.c index f5361cd8ccce..264d37243fad 100644 --- a/trunk/drivers/video/pmag-ba-fb.c +++ b/trunk/drivers/video/pmag-ba-fb.c @@ -15,7 +15,8 @@ * Michael Engel , * Karsten Merker and * Harald Koerfgen. - * Copyright (c) 2005 Maciej W. Rozycki + * Copyright (c) 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -28,26 +29,21 @@ #include #include #include +#include #include #include #include -#include - #include